1/* 2 * Copyright (C) 2022 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 {HierarchyTreeBuilder} from 'test/unit/hierarchy_tree_builder'; 19import {MockStorage} from 'test/unit/mock_storage'; 20import {TracesBuilder} from 'test/unit/traces_builder'; 21import {TraceBuilder} from 'test/unit/trace_builder'; 22import {UnitTestUtils} from 'test/unit/utils'; 23import {Traces} from 'trace/traces'; 24import {TracePosition} from 'trace/trace_position'; 25import {TraceType} from 'trace/trace_type'; 26import {ImeUiData} from 'viewers/common/ime_ui_data'; 27import {HierarchyTreeNode, PropertiesTreeNode} from 'viewers/common/ui_tree_utils'; 28import {UserOptions} from 'viewers/common/user_options'; 29import {PresenterInputMethodClients} from 'viewers/viewer_input_method_clients/presenter_input_method_clients'; 30import {PresenterInputMethodManagerService} from 'viewers/viewer_input_method_manager_service/presenter_input_method_manager_service'; 31import {PresenterInputMethodService} from 'viewers/viewer_input_method_service/presenter_input_method_service'; 32import {PresenterInputMethod} from './presenter_input_method'; 33 34export function executePresenterInputMethodTests( 35 selected: HierarchyTreeNode, 36 propertiesTreeFilterString: string, 37 expectedChildren: [number, number], 38 expectHierarchyTreeWithSfSubtree: boolean, 39 PresenterInputMethod: 40 | typeof PresenterInputMethodClients 41 | typeof PresenterInputMethodService 42 | typeof PresenterInputMethodManagerService, 43 imeTraceType: TraceType 44) { 45 describe('PresenterInputMethod', () => { 46 let presenter: PresenterInputMethod; 47 let uiData: ImeUiData; 48 let position: TracePosition; 49 let selectedTree: HierarchyTreeNode; 50 51 beforeEach(async () => { 52 selectedTree = selected; 53 await setUpTestEnvironment([ 54 imeTraceType, 55 TraceType.SURFACE_FLINGER, 56 TraceType.WINDOW_MANAGER, 57 ]); 58 }); 59 60 it('is robust to empty trace', async () => { 61 const traces = new TracesBuilder().setEntries(imeTraceType, []).build(); 62 presenter = createPresenter(traces); 63 64 expect(uiData.hierarchyUserOptions).toBeTruthy(); 65 expect(uiData.propertiesUserOptions).toBeTruthy(); 66 expect(uiData.tree).toBeFalsy(); 67 68 await presenter.onTracePositionUpdate(position); 69 expect(uiData.hierarchyUserOptions).toBeTruthy(); 70 expect(uiData.propertiesUserOptions).toBeTruthy(); 71 expect(uiData.tree).toBeFalsy(); 72 }); 73 74 it('is robust to traces without SF', async () => { 75 await setUpTestEnvironment([imeTraceType, TraceType.WINDOW_MANAGER]); 76 await presenter.onTracePositionUpdate(position); 77 expect(uiData.hierarchyUserOptions).toBeTruthy(); 78 expect(uiData.propertiesUserOptions).toBeTruthy(); 79 expect(Object.keys(uiData.tree!).length > 0).toBeTrue(); 80 }); 81 82 it('is robust to traces without WM', async () => { 83 await setUpTestEnvironment([imeTraceType, TraceType.SURFACE_FLINGER]); 84 await presenter.onTracePositionUpdate(position); 85 expect(uiData.hierarchyUserOptions).toBeTruthy(); 86 expect(uiData.propertiesUserOptions).toBeTruthy(); 87 expect(Object.keys(uiData.tree!).length > 0).toBeTrue(); 88 }); 89 90 it('is robust to traces without WM and SF', async () => { 91 await setUpTestEnvironment([imeTraceType]); 92 await presenter.onTracePositionUpdate(position); 93 expect(uiData.hierarchyUserOptions).toBeTruthy(); 94 expect(uiData.propertiesUserOptions).toBeTruthy(); 95 expect(Object.keys(uiData.tree!).length > 0).toBeTrue(); 96 }); 97 98 it('processes trace position updates', async () => { 99 await presenter.onTracePositionUpdate(position); 100 expect(uiData.hierarchyUserOptions).toBeTruthy(); 101 expect(uiData.propertiesUserOptions).toBeTruthy(); 102 expect(Object.keys(uiData.tree!).length > 0).toBeTrue(); 103 }); 104 105 it('can update pinned items', () => { 106 expect(uiData.pinnedItems).toEqual([]); 107 const pinnedItem = new HierarchyTreeBuilder() 108 .setName('FirstPinnedItem') 109 .setStableId('TestItem 4') 110 .setLayerId(4) 111 .build(); 112 presenter.updatePinnedItems(pinnedItem); 113 expect(uiData.pinnedItems).toContain(pinnedItem); 114 }); 115 116 it('can update highlighted items', () => { 117 expect(uiData.highlightedItems).toEqual([]); 118 const id = 'entry'; 119 presenter.updateHighlightedItems(id); 120 expect(uiData.highlightedItems).toContain(id); 121 }); 122 123 it('can update hierarchy tree', async () => { 124 //change flat view to true 125 const userOptions: UserOptions = { 126 onlyVisible: { 127 name: 'Only visible', 128 enabled: true, 129 }, 130 simplifyNames: { 131 name: 'Simplify names', 132 enabled: true, 133 }, 134 flat: { 135 name: 'Flat', 136 enabled: false, 137 }, 138 }; 139 140 let expectedChildren = expectHierarchyTreeWithSfSubtree ? 2 : 1; 141 await presenter.onTracePositionUpdate(position); 142 expect(uiData.tree?.children.length).toEqual(expectedChildren); 143 144 // Filter out non-visible child 145 expectedChildren = expectHierarchyTreeWithSfSubtree ? 1 : 0; 146 presenter.updateHierarchyTree(userOptions); 147 expect(uiData.hierarchyUserOptions).toEqual(userOptions); 148 expect(uiData.tree?.children.length).toEqual(expectedChildren); 149 }); 150 151 it('can filter hierarchy tree', async () => { 152 const userOptions: UserOptions = { 153 onlyVisible: { 154 name: 'Only visible', 155 enabled: false, 156 }, 157 simplifyNames: { 158 name: 'Simplify names', 159 enabled: true, 160 }, 161 flat: { 162 name: 'Flat', 163 enabled: true, 164 }, 165 }; 166 167 const expectedChildren = expectHierarchyTreeWithSfSubtree ? 12 : 1; 168 await presenter.onTracePositionUpdate(position); 169 presenter.updateHierarchyTree(userOptions); 170 expect(uiData.tree?.children.length).toEqual(expectedChildren); 171 172 // Filter out all children 173 presenter.filterHierarchyTree('Reject all'); 174 expect(uiData.tree?.children.length).toEqual(0); 175 }); 176 177 it('can set new properties tree and associated ui data', async () => { 178 await presenter.onTracePositionUpdate(position); 179 presenter.newPropertiesTree(selectedTree); 180 // does not check specific tree values as tree transformation method may change 181 expect(uiData.propertiesTree).toBeTruthy(); 182 }); 183 184 it('can filter properties tree', async () => { 185 await presenter.onTracePositionUpdate(position); 186 presenter.newPropertiesTree(selectedTree); 187 let nonTerminalChildren = 188 uiData.propertiesTree?.children?.filter( 189 (child: PropertiesTreeNode) => typeof child.propertyKey === 'string' 190 ) ?? []; 191 192 expect(nonTerminalChildren.length).toEqual(expectedChildren[0]); 193 presenter.filterPropertiesTree(propertiesTreeFilterString); 194 195 nonTerminalChildren = 196 uiData.propertiesTree?.children?.filter( 197 (child: PropertiesTreeNode) => typeof child.propertyKey === 'string' 198 ) ?? []; 199 expect(nonTerminalChildren.length).toEqual(expectedChildren[1]); 200 }); 201 202 const setUpTestEnvironment = async (traceTypes: TraceType[]) => { 203 const traces = new Traces(); 204 const entries = await UnitTestUtils.getImeTraceEntries(); 205 206 traceTypes.forEach((traceType) => { 207 const trace = new TraceBuilder<object>() 208 .setEntries([entries.get(traceType)]) 209 .setFrame(0, 0) 210 .build(); 211 traces.setTrace(traceType, trace); 212 }); 213 214 presenter = createPresenter(traces); 215 216 position = TracePosition.fromTraceEntry( 217 assertDefined(traces.getTrace(imeTraceType)).getEntry(0) 218 ); 219 }; 220 221 const createPresenter = (traces: Traces): PresenterInputMethod => { 222 return new PresenterInputMethod( 223 traces, 224 new MockStorage(), 225 [imeTraceType], 226 (newData: ImeUiData) => { 227 uiData = newData; 228 } 229 ); 230 }; 231 }); 232} 233