1// Copyright (C) 2018 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 {produce} from 'immer'; 16 17import {StateActions} from './actions'; 18import { 19 createEmptyState, 20 SCROLLING_TRACK_GROUP, 21 State, 22 TraceUrlSource, 23 TrackState, 24} from './state'; 25 26function fakeTrack(state: State, id: string): TrackState { 27 const track: TrackState = { 28 id, 29 engineId: '1', 30 kind: 'SOME_TRACK_KIND', 31 name: 'A track', 32 trackGroup: SCROLLING_TRACK_GROUP, 33 config: {}, 34 }; 35 state.tracks[id] = track; 36 return track; 37} 38 39test('navigate', () => { 40 const after = produce(createEmptyState(), draft => { 41 StateActions.navigate(draft, {route: '/foo'}); 42 }); 43 expect(after.route).toBe('/foo'); 44}); 45 46test('add scrolling tracks', () => { 47 const once = produce(createEmptyState(), draft => { 48 StateActions.addTrack(draft, { 49 engineId: '1', 50 kind: 'cpu', 51 name: 'Cpu 1', 52 trackGroup: SCROLLING_TRACK_GROUP, 53 config: {}, 54 }); 55 }); 56 const twice = produce(once, draft => { 57 StateActions.addTrack(draft, { 58 engineId: '2', 59 kind: 'cpu', 60 name: 'Cpu 2', 61 trackGroup: SCROLLING_TRACK_GROUP, 62 config: {}, 63 }); 64 }); 65 66 expect(Object.values(twice.tracks).length).toBe(2); 67 expect(twice.scrollingTracks.length).toBe(2); 68}); 69 70test('add track to track group', () => { 71 const state = createEmptyState(); 72 fakeTrack(state, 's'); 73 74 const afterGroup = produce(state, draft => { 75 StateActions.addTrackGroup(draft, { 76 engineId: '1', 77 name: 'A track group', 78 id: '123-123-123', 79 summaryTrackId: 's', 80 collapsed: false, 81 }); 82 }); 83 84 const afterTrackAdd = produce(afterGroup, draft => { 85 StateActions.addTrack(draft, { 86 id: '1', 87 engineId: '1', 88 kind: 'slices', 89 name: 'renderer 1', 90 trackGroup: '123-123-123', 91 config: {}, 92 }); 93 }); 94 95 expect(afterTrackAdd.trackGroups['123-123-123'].tracks[0]).toBe('1'); 96}); 97 98test('reorder tracks', () => { 99 const once = produce(createEmptyState(), draft => { 100 StateActions.addTrack(draft, { 101 engineId: '1', 102 kind: 'cpu', 103 name: 'Cpu 1', 104 config: {}, 105 }); 106 StateActions.addTrack(draft, { 107 engineId: '2', 108 kind: 'cpu', 109 name: 'Cpu 2', 110 config: {}, 111 }); 112 }); 113 114 const firstTrackId = once.scrollingTracks[0]; 115 const secondTrackId = once.scrollingTracks[1]; 116 117 const twice = produce(once, draft => { 118 StateActions.moveTrack(draft, { 119 srcId: `${firstTrackId}`, 120 op: 'after', 121 dstId: `${secondTrackId}`, 122 }); 123 }); 124 125 expect(twice.scrollingTracks[0]).toBe(secondTrackId); 126 expect(twice.scrollingTracks[1]).toBe(firstTrackId); 127}); 128 129test('reorder pinned to scrolling', () => { 130 const state = createEmptyState(); 131 fakeTrack(state, 'a'); 132 fakeTrack(state, 'b'); 133 fakeTrack(state, 'c'); 134 state.pinnedTracks = ['a', 'b']; 135 state.scrollingTracks = ['c']; 136 137 const after = produce(state, draft => { 138 StateActions.moveTrack(draft, { 139 srcId: 'b', 140 op: 'before', 141 dstId: 'c', 142 }); 143 }); 144 145 expect(after.pinnedTracks).toEqual(['a']); 146 expect(after.scrollingTracks).toEqual(['b', 'c']); 147}); 148 149test('reorder scrolling to pinned', () => { 150 const state = createEmptyState(); 151 fakeTrack(state, 'a'); 152 fakeTrack(state, 'b'); 153 fakeTrack(state, 'c'); 154 state.pinnedTracks = ['a']; 155 state.scrollingTracks = ['b', 'c']; 156 157 const after = produce(state, draft => { 158 StateActions.moveTrack(draft, { 159 srcId: 'b', 160 op: 'after', 161 dstId: 'a', 162 }); 163 }); 164 165 expect(after.pinnedTracks).toEqual(['a', 'b']); 166 expect(after.scrollingTracks).toEqual(['c']); 167}); 168 169test('reorder clamp bottom', () => { 170 const state = createEmptyState(); 171 fakeTrack(state, 'a'); 172 fakeTrack(state, 'b'); 173 fakeTrack(state, 'c'); 174 state.pinnedTracks = ['a', 'b']; 175 state.scrollingTracks = ['c']; 176 177 const after = produce(state, draft => { 178 StateActions.moveTrack(draft, { 179 srcId: 'a', 180 op: 'before', 181 dstId: 'a', 182 }); 183 }); 184 expect(after).toEqual(state); 185}); 186 187test('reorder clamp top', () => { 188 const state = createEmptyState(); 189 fakeTrack(state, 'a'); 190 fakeTrack(state, 'b'); 191 fakeTrack(state, 'c'); 192 state.pinnedTracks = ['a']; 193 state.scrollingTracks = ['b', 'c']; 194 195 const after = produce(state, draft => { 196 StateActions.moveTrack(draft, { 197 srcId: 'c', 198 op: 'after', 199 dstId: 'c', 200 }); 201 }); 202 expect(after).toEqual(state); 203}); 204 205test('pin', () => { 206 const state = createEmptyState(); 207 fakeTrack(state, 'a'); 208 fakeTrack(state, 'b'); 209 fakeTrack(state, 'c'); 210 state.pinnedTracks = ['a']; 211 state.scrollingTracks = ['b', 'c']; 212 213 const after = produce(state, draft => { 214 StateActions.toggleTrackPinned(draft, { 215 trackId: 'c', 216 }); 217 }); 218 expect(after.pinnedTracks).toEqual(['a', 'c']); 219 expect(after.scrollingTracks).toEqual(['b']); 220}); 221 222test('unpin', () => { 223 const state = createEmptyState(); 224 fakeTrack(state, 'a'); 225 fakeTrack(state, 'b'); 226 fakeTrack(state, 'c'); 227 state.pinnedTracks = ['a', 'b']; 228 state.scrollingTracks = ['c']; 229 230 const after = produce(state, draft => { 231 StateActions.toggleTrackPinned(draft, { 232 trackId: 'a', 233 }); 234 }); 235 expect(after.pinnedTracks).toEqual(['b']); 236 expect(after.scrollingTracks).toEqual(['a', 'c']); 237}); 238 239test('open trace', () => { 240 const state = createEmptyState(); 241 state.nextId = 100; 242 const recordConfig = state.recordConfig; 243 const after = produce(state, draft => { 244 StateActions.openTraceFromUrl(draft, { 245 url: 'https://example.com/bar', 246 }); 247 }); 248 249 const engineKeys = Object.keys(after.engines); 250 expect(after.nextId).toBe(101); 251 expect(engineKeys.length).toBe(1); 252 expect((after.engines[engineKeys[0]].source as TraceUrlSource).url) 253 .toBe('https://example.com/bar'); 254 expect(after.route).toBe('/viewer'); 255 expect(after.recordConfig).toBe(recordConfig); 256}); 257 258test('open second trace from file', () => { 259 const once = produce(createEmptyState(), draft => { 260 StateActions.openTraceFromUrl(draft, { 261 url: 'https://example.com/bar', 262 }); 263 }); 264 265 const twice = produce(once, draft => { 266 StateActions.addTrack(draft, { 267 engineId: '1', 268 kind: 'cpu', 269 name: 'Cpu 1', 270 config: {}, 271 }); 272 }); 273 274 const thrice = produce(twice, draft => { 275 StateActions.openTraceFromUrl(draft, { 276 url: 'https://example.com/foo', 277 }); 278 }); 279 280 const engineKeys = Object.keys(thrice.engines); 281 expect(engineKeys.length).toBe(1); 282 expect((thrice.engines[engineKeys[0]].source as TraceUrlSource).url) 283 .toBe('https://example.com/foo'); 284 expect(thrice.pinnedTracks.length).toBe(0); 285 expect(thrice.scrollingTracks.length).toBe(0); 286 expect(thrice.route).toBe('/viewer'); 287}); 288