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 {TransformType} from 'parsers/surface_flinger/transform_utils';
19import {
20  TamperedMessageType,
21  TamperedProtoField,
22} from 'parsers/tampered_message_type';
23import root from 'protos/test/fake_proto/json';
24import {PropertyTreeBuilder} from 'test/unit/property_tree_builder';
25import {TreeNodeUtils} from 'test/unit/tree_node_utils';
26import {EMPTY_OBJ_STRING, LAYER_ID_FORMATTER} from 'trace/tree_node/formatters';
27import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
28import {SetFormatters} from './set_formatters';
29
30describe('SetFormatters', () => {
31  let propertyRoot: PropertyTreeNode;
32  let operation: SetFormatters;
33  let field: TamperedProtoField;
34
35  beforeEach(() => {
36    field = TamperedMessageType.tamper(root.lookupType('RootMessage')).fields[
37      'entry'
38    ];
39  });
40
41  it('adds correct formatter for enum node', () => {
42    propertyRoot = new PropertyTreeBuilder()
43      .setIsRoot(true)
44      .setRootId('test')
45      .setName('node')
46      .setChildren([{name: 'enum0', value: 0}])
47      .build();
48    operation = new SetFormatters(field);
49    operation.apply(propertyRoot);
50
51    expect(propertyRoot.formattedValue()).toEqual('');
52    expect(propertyRoot.getChildByName('enum0')?.formattedValue()).toEqual(
53      'ENUM0_VALUE_ZERO',
54    );
55  });
56
57  it('adds correct formatter for color node', () => {
58    propertyRoot = new PropertyTreeBuilder()
59      .setIsRoot(true)
60      .setRootId('test')
61      .setName('node')
62      .build();
63    propertyRoot.addOrReplaceChild(TreeNodeUtils.makeColorNode(-1, -1, -1, 1));
64    operation = new SetFormatters();
65    operation.apply(propertyRoot);
66
67    expect(propertyRoot.formattedValue()).toEqual('');
68    expect(
69      assertDefined(propertyRoot.getChildByName('color')).formattedValue(),
70    ).toEqual(`${EMPTY_OBJ_STRING}, alpha: 1`);
71  });
72
73  it('adds correct formatter for color3 node', () => {
74    propertyRoot = new PropertyTreeBuilder()
75      .setIsRoot(true)
76      .setRootId('test')
77      .setName('node')
78      .build();
79    propertyRoot.addOrReplaceChild(
80      TreeNodeUtils.makeColorNode(0, 0, 0, undefined),
81    );
82    operation = new SetFormatters();
83    operation.apply(propertyRoot);
84
85    expect(propertyRoot.formattedValue()).toEqual('');
86    expect(
87      assertDefined(propertyRoot.getChildByName('color')).formattedValue(),
88    ).toEqual(`(0, 0, 0)`);
89  });
90
91  it('adds correct formatter for rect node', () => {
92    propertyRoot = new PropertyTreeBuilder()
93      .setIsRoot(true)
94      .setRootId('test')
95      .setName('node')
96      .build();
97    propertyRoot.addOrReplaceChild(TreeNodeUtils.makeRectNode(0, 0, 1, 1));
98    operation = new SetFormatters();
99    operation.apply(propertyRoot);
100
101    expect(propertyRoot.formattedValue()).toEqual('');
102    expect(
103      assertDefined(propertyRoot.getChildByName('rect')).formattedValue(),
104    ).toEqual('(0, 0) - (1, 1)');
105  });
106
107  it('adds correct formatter for buffer node', () => {
108    propertyRoot = new PropertyTreeBuilder()
109      .setIsRoot(true)
110      .setRootId('test')
111      .setName('node')
112      .build();
113    propertyRoot.addOrReplaceChild(TreeNodeUtils.makeBufferNode());
114    operation = new SetFormatters();
115    operation.apply(propertyRoot);
116
117    expect(propertyRoot.formattedValue()).toEqual('');
118    expect(
119      assertDefined(propertyRoot.getChildByName('buffer')).formattedValue(),
120    ).toEqual('w: 1, h: 0, stride: 0, format: 1');
121  });
122
123  it('adds correct formatter for size node', () => {
124    propertyRoot = new PropertyTreeBuilder()
125      .setIsRoot(true)
126      .setRootId('test')
127      .setName('node')
128      .build();
129    propertyRoot.addOrReplaceChild(TreeNodeUtils.makeSizeNode(1, 2));
130    operation = new SetFormatters();
131    operation.apply(propertyRoot);
132
133    expect(propertyRoot.formattedValue()).toEqual('');
134    expect(
135      assertDefined(propertyRoot.getChildByName('size')).formattedValue(),
136    ).toEqual('1 x 2');
137  });
138
139  it('adds correct formatter for region node', () => {
140    propertyRoot = new PropertyTreeBuilder()
141      .setIsRoot(true)
142      .setRootId('test')
143      .setName('node')
144      .setChildren([
145        {
146          name: 'region',
147          value: undefined,
148          children: [
149            {
150              name: 'rect',
151              value: undefined,
152              children: [
153                {
154                  name: '0',
155                  value: undefined,
156                  children: [
157                    {name: 'left', value: 0},
158                    {name: 'top', value: 0},
159                    {name: 'right', value: 1},
160                    {name: 'bottom', value: 1},
161                  ],
162                },
163              ],
164            },
165          ],
166        },
167      ])
168      .build();
169    operation = new SetFormatters();
170    operation.apply(propertyRoot);
171
172    expect(propertyRoot.formattedValue()).toEqual('');
173    expect(
174      assertDefined(propertyRoot.getChildByName('region')).formattedValue(),
175    ).toEqual('SkRegion((0, 0, 1, 1))');
176  });
177
178  it('adds correct formatter for position node', () => {
179    propertyRoot = new PropertyTreeBuilder()
180      .setIsRoot(true)
181      .setRootId('test')
182      .setName('node')
183      .build();
184    propertyRoot.addOrReplaceChild(TreeNodeUtils.makePositionNode(1, 2));
185    operation = new SetFormatters();
186    operation.apply(propertyRoot);
187
188    expect(propertyRoot.formattedValue()).toEqual('');
189    expect(
190      assertDefined(propertyRoot.getChildByName('pos')).formattedValue(),
191    ).toEqual('x: 1, y: 2');
192  });
193
194  it('adds correct formatter for transform node', () => {
195    propertyRoot = new PropertyTreeBuilder()
196      .setIsRoot(true)
197      .setRootId('test')
198      .setName('node')
199      .build();
200    propertyRoot.addOrReplaceChild(
201      TreeNodeUtils.makeTransformNode(TransformType.EMPTY),
202    );
203    operation = new SetFormatters();
204    operation.apply(propertyRoot);
205
206    expect(propertyRoot.formattedValue()).toEqual('');
207    expect(
208      assertDefined(propertyRoot.getChildByName('transform')).formattedValue(),
209    ).toEqual('IDENTITY');
210  });
211
212  it('does not add formatter to unrecognised nested property', () => {
213    propertyRoot = new PropertyTreeBuilder()
214      .setIsRoot(true)
215      .setRootId('test')
216      .setName('node')
217      .setChildren([
218        {name: 'nestedProperty', children: [{name: 'val', value: 1}]},
219      ])
220      .build();
221
222    operation = new SetFormatters();
223    operation.apply(propertyRoot);
224
225    expect(propertyRoot.formattedValue()).toEqual('');
226    const propertyWithFormatters = assertDefined(
227      propertyRoot.getChildByName('nestedProperty'),
228    );
229    expect(propertyWithFormatters.formattedValue()).toEqual('');
230    expect(
231      assertDefined(
232        propertyWithFormatters.getChildByName('val'),
233      ).formattedValue(),
234    ).toEqual('1');
235  });
236
237  it('adds correct formatter for simple leaf property', () => {
238    propertyRoot = new PropertyTreeBuilder()
239      .setIsRoot(true)
240      .setRootId('test')
241      .setName('node')
242      .setChildren([{name: 'val', value: 1}])
243      .build();
244
245    operation = new SetFormatters();
246    operation.apply(propertyRoot);
247
248    expect(propertyRoot.formattedValue()).toEqual('');
249    expect(
250      assertDefined(propertyRoot.getChildByName('val')).formattedValue(),
251    ).toEqual('1');
252  });
253
254  it('adds custom formatter', () => {
255    propertyRoot = new PropertyTreeBuilder()
256      .setIsRoot(true)
257      .setRootId('test')
258      .setName('node')
259      .setChildren([{name: 'layerId', value: -1}])
260      .build();
261    operation = new SetFormatters(
262      undefined,
263      new Map([['layerId', LAYER_ID_FORMATTER]]),
264    );
265    operation.apply(propertyRoot);
266
267    expect(propertyRoot.formattedValue()).toEqual('');
268    expect(
269      assertDefined(propertyRoot.getChildByName('layerId')).formattedValue(),
270    ).toEqual('none');
271  });
272});
273