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. 15 */ 16 17import {assertDefined} from 'common/assert_utils'; 18import {HierarchyTreeBuilder} from 'test/unit/hierarchy_tree_builder'; 19import {PropertyTreeBuilder} from 'test/unit/property_tree_builder'; 20import {TreeNodeUtils} from 'test/unit/tree_node_utils'; 21import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 22import {PropertySource} from 'trace/tree_node/property_tree_node'; 23import {TextFilter} from 'viewers/common/text_filter'; 24import {DiffType} from './diff_type'; 25import {PropertiesPresenter} from './properties_presenter'; 26import {UiPropertyTreeNode} from './ui_property_tree_node'; 27 28describe('PropertiesPresenter', () => { 29 const pTree = new PropertyTreeBuilder() 30 .setIsRoot(true) 31 .setRootId('Test Trace') 32 .setName('entry') 33 .setChildren([ 34 {name: 'defProp', value: false, source: PropertySource.DEFAULT}, 35 {name: 'setProp', value: 1}, 36 {name: 'otherProp', value: 2}, 37 {name: 'calcProp', value: true, source: PropertySource.CALCULATED}, 38 ]) 39 .build(); 40 const hTree = new HierarchyTreeBuilder() 41 .setId('Test Trace') 42 .setName('entry') 43 .setProperties({setProp: 2}) 44 .build(); 45 let presenter: PropertiesPresenter; 46 47 beforeAll(async () => { 48 jasmine.addCustomEqualityTester(TreeNodeUtils.treeNodeEqualityTester); 49 }); 50 51 beforeEach(() => { 52 presenter = new PropertiesPresenter({}, new TextFilter(), []); 53 presenter.setPropertiesTree(pTree); 54 }); 55 56 it('exposes user options', () => { 57 expect(presenter.getUserOptions()).toEqual({}); 58 const testOptions = {test: {name: 'Test opt', enabled: false}}; 59 presenter.applyPropertiesUserOptionsChange(testOptions); 60 expect(presenter.getUserOptions()).toEqual(testOptions); 61 }); 62 63 it('updates highlighted property', () => { 64 expect(presenter.getHighlightedProperty()).toEqual(''); 65 const id = '4'; 66 presenter.applyHighlightedPropertyChange(id); 67 expect(presenter.getHighlightedProperty()).toEqual(id); 68 presenter.applyHighlightedPropertyChange(id); 69 expect(presenter.getHighlightedProperty()).toEqual(''); 70 }); 71 72 it('updates properties tree to show diffs based on user option', async () => { 73 let formattedTree = await getFormattedTree(hTree); 74 expect(getDiff(formattedTree, 'setProp')).toEqual(DiffType.NONE); 75 expect(getDiff(formattedTree, 'otherProp')).toEqual(DiffType.NONE); 76 77 presenter.applyPropertiesUserOptionsChange({ 78 showDiff: {name: '', enabled: true}, 79 }); 80 formattedTree = await getFormattedTree(); 81 expect(getDiff(formattedTree, 'setProp')).toEqual(DiffType.ADDED); 82 expect(getDiff(formattedTree, 'otherProp')).toEqual(DiffType.ADDED); 83 84 formattedTree = await getFormattedTree(hTree); 85 formattedTree = assertDefined(presenter.getFormattedTree()); 86 expect(getDiff(formattedTree, 'setProp')).toEqual(DiffType.MODIFIED); 87 expect(getDiff(formattedTree, 'otherProp')).toEqual(DiffType.ADDED); 88 }); 89 90 it('shows/hides defaults based on user option', async () => { 91 expect((await getFormattedTree()).getAllChildren().length).toEqual(2); 92 presenter.applyPropertiesUserOptionsChange({ 93 showDefaults: {name: '', enabled: true}, 94 }); 95 expect((await getFormattedTree()).getAllChildren().length).toEqual(3); 96 }); 97 98 it('filters properties tree', async () => { 99 expect((await getFormattedTree()).getAllChildren().length).toEqual(2); 100 const filter = new TextFilter('setProp'); 101 presenter.applyPropertiesFilterChange(filter); 102 expect(presenter.getTextFilter()).toEqual(filter); 103 expect((await getFormattedTree()).getAllChildren().length).toEqual(1); 104 }); 105 106 it('keeps calculated properties', async () => { 107 const tree = await getFormattedTree(undefined, undefined, true); 108 expect(tree.getAllChildren().length).toEqual(3); 109 }); 110 111 it('overrides display name', async () => { 112 const tree = await getFormattedTree(undefined, 'Override Name'); 113 expect(tree.getDisplayName()).toEqual('Override Name'); 114 }); 115 116 it('keeps allowlist default properties', async () => { 117 presenter.updateDefaultAllowList(['defProp']); 118 expect((await getFormattedTree()).getChildByName('defProp')).toBeDefined(); 119 }); 120 121 it('discards denylist properties', async () => { 122 presenter = new PropertiesPresenter({}, new TextFilter(), ['setProp']); 123 presenter.setPropertiesTree(pTree); 124 const tree = await getFormattedTree(); 125 expect(tree.getChildByName('setProp')).toBeUndefined(); 126 }); 127 128 it('applies custom operations', async () => { 129 const operation = jasmine.createSpyObj('operation', ['apply']); 130 presenter = new PropertiesPresenter({}, new TextFilter(), [], [operation]); 131 presenter.setPropertiesTree(pTree); 132 await getFormattedTree(); 133 expect(operation.apply).toHaveBeenCalledTimes(1); 134 }); 135 136 function getDiff(tree: UiPropertyTreeNode, propertyName: string): DiffType { 137 return assertDefined(tree.getChildByName(propertyName)).getDiff(); 138 } 139 140 async function getFormattedTree( 141 previousHierarchyTree?: HierarchyTreeNode, 142 displayName?: string, 143 keepCalculated = false, 144 ): Promise<UiPropertyTreeNode> { 145 await presenter.formatPropertiesTree( 146 previousHierarchyTree, 147 displayName, 148 keepCalculated, 149 ); 150 return assertDefined(presenter.getFormattedTree()); 151 } 152}); 153