xref: /aosp_15_r20/external/perfetto/ui/src/public/workspace_unittest.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2023 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {TrackNode, Workspace} from './workspace';
16
17describe('workspace', () => {
18  test('getNodeByKey', () => {
19    const workspace = new Workspace();
20    const track = new TrackNode({id: 'foo'});
21    workspace.addChildLast(track);
22
23    expect(workspace.getTrackById('foo')).toEqual(track);
24  });
25
26  test('getNodeByKey', () => {
27    const track = new TrackNode({id: 'bar'});
28
29    const group = new TrackNode();
30    group.addChildLast(track);
31
32    // Add group to workspace AFTER adding the track to the group
33    const workspace = new Workspace();
34    workspace.addChildLast(group);
35
36    expect(workspace.getTrackById('bar')).toBe(track);
37  });
38
39  test('nested index lookup', () => {
40    const track = new TrackNode({id: 'bar'});
41
42    const group = new TrackNode();
43
44    // Add group to workspace before adding the track to the group
45    const workspace = new Workspace();
46    workspace.addChildLast(group);
47    group.addChildLast(track);
48
49    expect(workspace.getTrackById('bar')).toBe(track);
50  });
51
52  test('nested index lookup', () => {
53    const workspace = new Workspace();
54
55    const group = new TrackNode();
56
57    const track = new TrackNode({id: 'bar'});
58    group.addChildLast(track);
59
60    // Add group to workspace
61    workspace.addChildLast(group);
62    workspace.removeChild(group);
63
64    expect(workspace.getTrackById('bar')).toBe(undefined);
65  });
66
67  test('findTrackByUri()', () => {
68    const workspace = new Workspace();
69
70    const group = new TrackNode();
71
72    const track = new TrackNode({uri: 'foo'});
73    group.addChildLast(track);
74
75    // Add group to workspace
76    workspace.addChildLast(group);
77
78    expect(workspace.findTrackByUri('foo')).toBe(track);
79  });
80
81  test('findClosestVisibleAncestor()', () => {
82    const child = new TrackNode();
83    child.expand(); // Expanding the child node should have no effect
84
85    const parent = new TrackNode();
86    parent.expand();
87    parent.addChildLast(child);
88
89    // While everything is expanded and the child node is visible, the child
90    // should be returned.
91    expect(child.findClosestVisibleAncestor()).toBe(child);
92
93    // Collapse the parent node and this parent should be returned, as from the
94    // point of view of the root, this is the closest we can get to our target
95    // node without expanding any more nodes.
96    parent.collapse();
97    expect(child.findClosestVisibleAncestor()).toBe(parent);
98  });
99});
100
101describe('TrackNode.addChildInOrder', () => {
102  let container: TrackNode;
103
104  beforeEach(() => {
105    container = new TrackNode();
106  });
107
108  test('inserts a child into an empty container', () => {
109    const child = new TrackNode({id: 'track1'});
110
111    container.addChildInOrder(child);
112
113    expect(container.children).toHaveLength(1);
114    expect(container.children[0]).toBe(child);
115  });
116
117  test('inserts a child with a lower sortOrder before an existing child', () => {
118    const child1 = new TrackNode({sortOrder: 10});
119    const child2 = new TrackNode({sortOrder: 5});
120
121    container.addChildInOrder(child1);
122    container.addChildInOrder(child2);
123
124    expect(container.children).toHaveLength(2);
125    expect(container.children[0]).toBe(child2);
126    expect(container.children[1]).toBe(child1);
127  });
128
129  test('inserts a child with a higher sortOrder after an existing child', () => {
130    const child1 = new TrackNode({sortOrder: 5});
131    const child2 = new TrackNode({sortOrder: 10});
132
133    container.addChildInOrder(child1);
134    container.addChildInOrder(child2);
135
136    expect(container.children).toHaveLength(2);
137    expect(container.children[0]).toBe(child1);
138    expect(container.children[1]).toBe(child2);
139  });
140
141  test('inserts a child with the same sortOrder after an existing child', () => {
142    const child1 = new TrackNode({sortOrder: 5});
143    const child2 = new TrackNode({sortOrder: 5});
144
145    container.addChildInOrder(child1);
146    container.addChildInOrder(child2);
147
148    expect(container.children).toHaveLength(2);
149    expect(container.children[0]).toBe(child1);
150    expect(container.children[1]).toBe(child2);
151  });
152
153  test('inserts multiple children and maintains order', () => {
154    const child1 = new TrackNode({sortOrder: 15});
155    const child2 = new TrackNode({sortOrder: 10});
156    const child3 = new TrackNode({sortOrder: 20});
157
158    container.addChildInOrder(child1);
159    container.addChildInOrder(child2);
160    container.addChildInOrder(child3);
161
162    expect(container.children).toHaveLength(3);
163    expect(container.children[0]).toBe(child2);
164    expect(container.children[1]).toBe(child1);
165    expect(container.children[2]).toBe(child3);
166  });
167
168  test('inserts a child with undefined sortOrder as 0', () => {
169    const child1 = new TrackNode({sortOrder: 10});
170
171    // sortOrder is undefined, treated as 0
172    const child2 = new TrackNode();
173
174    container.addChildInOrder(child1);
175    container.addChildInOrder(child2);
176
177    expect(container.children).toHaveLength(2);
178
179    // child2 (sortOrder 0) should be first
180    expect(container.children[0]).toBe(child2);
181    expect(container.children[1]).toBe(child1);
182  });
183});
184
185test('TrackNode::flatTracksOrdered', () => {
186  const root = new TrackNode();
187
188  const removeme = new TrackNode({id: 'removeme'});
189  root.addChildFirst(removeme);
190
191  const foo = new TrackNode({id: 'foo'});
192  root.addChildLast(foo);
193  foo.addChildLast(new TrackNode({id: 'fooBar'})); // <-- Note this one is added as a child of foo
194  const bar = new TrackNode({id: 'bar'});
195  root.addChildLast(bar);
196  root.addChildFirst(new TrackNode({id: 'baz'})); // <- Note this one is added first so should appear before the others in flatTracks
197
198  root.removeChild(removeme);
199
200  expect(root.flatTracksOrdered.map(({id}) => id)).toEqual([
201    'baz',
202    'foo',
203    'fooBar',
204    'bar',
205  ]);
206});
207
208test('TrackNode::flatTracks', () => {
209  const root = new TrackNode();
210
211  const removeme = new TrackNode({id: 'removeme'});
212  root.addChildFirst(removeme);
213
214  const foo = new TrackNode({id: 'foo'});
215  root.addChildLast(foo);
216  foo.addChildLast(new TrackNode({id: 'fooBar'})); // <-- Note this one is added as a child of foo
217  root.addChildLast(new TrackNode({id: 'bar'}));
218  root.addChildFirst(new TrackNode({id: 'baz'})); // <- Note this one is added first so should appear before the others in flatTracks
219
220  root.removeChild(removeme);
221
222  expect(root.flatTracks.map(({id}) => id)).toEqual(
223    expect.arrayContaining(['baz', 'foo', 'fooBar', 'bar']),
224  );
225  expect(root.flatTracks.length).toBe(4);
226});
227