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 {TracePositionUpdate} from 'messaging/winscope_event'; 19import {TimestampConverterUtils} from 'test/unit/timestamp_converter_utils'; 20import { 21 AbstractLogViewerPresenter, 22 NotifyLogViewCallbackType, 23} from './abstract_log_viewer_presenter'; 24import {LogSelectFilter, LogTextFilter} from './log_filters'; 25import {LogHeader, UiDataLog} from './ui_data_log'; 26 27export abstract class AbstractLogViewerPresenterTest<UiData extends UiDataLog> { 28 execute() { 29 describe('Common tests', () => { 30 let uiData: UiData; 31 let presenter: AbstractLogViewerPresenter<UiData, object>; 32 33 beforeAll(async () => { 34 await this.setUpTestEnvironment(); 35 }); 36 37 beforeEach(async () => { 38 jasmine.addCustomEqualityTester(filterEqualityTester); 39 presenter = await this.createPresenter((newData) => { 40 uiData = newData; 41 }); 42 if (this.resetTestEnvironment) { 43 this.resetTestEnvironment(); 44 } 45 }); 46 47 it('is robust to empty trace', async () => { 48 const presenter = await this.createPresenterWithEmptyTrace( 49 (newData: UiData) => (uiData = newData), 50 ); 51 await presenter.onAppEvent( 52 TracePositionUpdate.fromTimestamp( 53 TimestampConverterUtils.makeRealTimestamp(0n), 54 ), 55 ); 56 for (const [index, expectedHeader] of this.expectedHeaders.entries()) { 57 const header = uiData.headers[index]; 58 expect(header.spec).toEqual(expectedHeader.header.spec); 59 if (expectedHeader.options) { 60 expect((header.filter as LogSelectFilter)?.options).toEqual([]); 61 } 62 } 63 if (this.executePropertiesChecksForEmptyTrace) { 64 this.executePropertiesChecksForEmptyTrace(uiData); 65 } 66 }); 67 68 it('processes trace position updates', async () => { 69 await assertDefined(presenter).onAppEvent( 70 assertDefined(this.getPositionUpdate()), 71 ); 72 for (const [index, expectedHeader] of this.expectedHeaders.entries()) { 73 const header = uiData.headers[index]; 74 expect(header).toEqual(expectedHeader.header); 75 if (expectedHeader.options) { 76 expect((header.filter as LogSelectFilter).options).toEqual( 77 expectedHeader.options, 78 ); 79 } 80 } 81 if (this.executePropertiesChecksAfterPositionUpdate) { 82 this.executePropertiesChecksAfterPositionUpdate(uiData); 83 } 84 }); 85 }); 86 87 function filterEqualityTester( 88 first: any, 89 second: any, 90 ): boolean | undefined { 91 if (first instanceof LogTextFilter && second instanceof LogTextFilter) { 92 return ( 93 first.textFilter.filterString === second.textFilter.filterString && 94 first.textFilter.flags.length === second.textFilter.flags.length && 95 first.textFilter.flags.every( 96 (flag, index) => flag === second.textFilter.flags[index], 97 ) 98 ); 99 } 100 if ( 101 first instanceof LogSelectFilter && 102 second instanceof LogSelectFilter 103 ) { 104 return ( 105 first.options.length === second.options.length && 106 first.shouldFilterBySubstring === second.shouldFilterBySubstring 107 ); 108 } 109 return undefined; 110 } 111 112 if (this.executeSpecializedTests) { 113 this.executeSpecializedTests(); 114 } 115 } 116 117 abstract readonly expectedHeaders: Array<{ 118 header: LogHeader; 119 options?: string[]; 120 }>; 121 122 abstract setUpTestEnvironment(): Promise<void>; 123 abstract createPresenter( 124 callback: NotifyLogViewCallbackType<UiData>, 125 ): Promise<AbstractLogViewerPresenter<UiData, object>>; 126 abstract createPresenterWithEmptyTrace( 127 callback: NotifyLogViewCallbackType<UiData>, 128 ): Promise<AbstractLogViewerPresenter<UiData, object>>; 129 abstract getPositionUpdate(): TracePositionUpdate; 130 131 resetTestEnvironment?(): void; 132 executePropertiesChecksForEmptyTrace?(uiData: UiDataLog): void; 133 executePropertiesChecksAfterPositionUpdate?(uiData: UiDataLog): void; 134 executeSpecializedTests?(): void; 135} 136