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 {UiRectBuilder} from 'viewers/components/rects/ui_rect_builder';
18import {RectFilter} from './rect_filter';
19import {RectShowState} from './rect_show_state';
20
21describe('RectFilter', () => {
22  let rectFilter: RectFilter;
23  const nonVisibleRect = makeRect('nonVisibleRect', false);
24  const visibleRect = makeRect('visibleRect', true);
25  const displayRect = makeRect('displayRect', false, true);
26  const allRects = [visibleRect, nonVisibleRect, displayRect];
27  const preFilteredRects = [visibleRect, nonVisibleRect];
28  let expectedRectIdToShowState: Map<string, RectShowState>;
29
30  beforeEach(() => {
31    rectFilter = new RectFilter();
32    expectedRectIdToShowState = new Map([
33      [visibleRect.id, RectShowState.SHOW],
34      [nonVisibleRect.id, RectShowState.SHOW],
35      [displayRect.id, RectShowState.SHOW],
36    ]);
37  });
38
39  it('creates rect id to show state map', () => {
40    expect(rectFilter.getRectIdToShowState(allRects, allRects)).toEqual(
41      expectedRectIdToShowState,
42    );
43
44    // sets hide state for rect that is not present in filtered rects
45    expectedRectIdToShowState.set(displayRect.id, RectShowState.HIDE);
46    expect(rectFilter.getRectIdToShowState(allRects, preFilteredRects)).toEqual(
47      expectedRectIdToShowState,
48    );
49
50    // keeps rect that is not present in drawn rects but has force-show state
51    rectFilter.updateRectShowState(displayRect.id, RectShowState.SHOW);
52    expectedRectIdToShowState.set(displayRect.id, RectShowState.SHOW);
53    expect(rectFilter.getRectIdToShowState(allRects, preFilteredRects)).toEqual(
54      expectedRectIdToShowState,
55    );
56  });
57
58  it('updates rect forced show state', () => {
59    expect(isShown(visibleRect.id)).toBeTrue();
60
61    // robust to same state (RectShowState.SHOW)
62    rectFilter.updateRectShowState(visibleRect.id, RectShowState.SHOW);
63    expect(isShown(visibleRect.id)).toBeTrue();
64
65    rectFilter.updateRectShowState(visibleRect.id, RectShowState.HIDE);
66    expect(isShown(visibleRect.id)).toBeFalse();
67
68    // robust to same state (RectShowState.HIDE)
69    rectFilter.updateRectShowState(visibleRect.id, RectShowState.HIDE);
70    expect(isShown(visibleRect.id)).toBeFalse();
71
72    rectFilter.updateRectShowState(visibleRect.id, RectShowState.SHOW);
73    expect(isShown(visibleRect.id)).toBeTrue();
74
75    expect(isShown(displayRect.id)).toBeFalse();
76    rectFilter.updateRectShowState(displayRect.id, RectShowState.SHOW);
77    expect(isShown(displayRect.id)).toBeTrue();
78  });
79
80  it('does not filter rects if applicable', () => {
81    expect(rectFilter.filterRects(allRects, false, true)).toEqual(allRects);
82  });
83
84  it('filters non visible rects', () => {
85    const filteredRects = rectFilter.filterRects(allRects, true, true);
86    expect(filteredRects).toEqual([visibleRect, displayRect]);
87
88    // robust to all visible rects
89    expect(rectFilter.filterRects(filteredRects, true, true)).toEqual(
90      filteredRects,
91    );
92
93    // does not apply force-hide state
94    rectFilter.updateRectShowState(visibleRect.id, RectShowState.HIDE);
95    expect(rectFilter.filterRects(allRects, true, true)).toEqual(filteredRects);
96
97    // does not apply force-show state
98    rectFilter.updateRectShowState(nonVisibleRect.id, RectShowState.SHOW);
99    expect(rectFilter.filterRects(allRects, true, true)).toEqual(filteredRects);
100  });
101
102  it('applies show/hide states', () => {
103    rectFilter.updateRectShowState(visibleRect.id, RectShowState.HIDE);
104    const filteredRects = rectFilter.filterRects(allRects, false, false);
105    expect(filteredRects).toEqual([nonVisibleRect, displayRect]);
106
107    // robust to no change in show/hide states
108    expect(rectFilter.filterRects(filteredRects, false, false)).toEqual(
109      filteredRects,
110    );
111
112    rectFilter.updateRectShowState(visibleRect.id, RectShowState.SHOW);
113    expect(rectFilter.filterRects(allRects, false, false)).toEqual(allRects);
114  });
115
116  it('filters non visible rects and applies show/hide states', () => {
117    // does not remove force-shown non-visible rect
118    rectFilter.updateRectShowState(nonVisibleRect.id, RectShowState.SHOW);
119    expect(rectFilter.filterRects(allRects, true, false)).toEqual(allRects);
120
121    // removes force-hidden visible rect
122    rectFilter.updateRectShowState(visibleRect.id, RectShowState.HIDE);
123    const filteredRects = rectFilter.filterRects(allRects, true, false);
124    expect(filteredRects).toEqual([nonVisibleRect, displayRect]);
125
126    // removes non-visible rect but keeps visible rect that has not had hide/show state applied
127    rectFilter.updateRectShowState(nonVisibleRect.id, RectShowState.HIDE);
128    expect(rectFilter.filterRects(allRects, true, false)).toEqual([
129      displayRect,
130    ]);
131  });
132
133  function isShown(rectId: string) {
134    const nonHiddenRectIds = rectFilter.getRectIdToShowState(
135      allRects,
136      preFilteredRects,
137    );
138    return nonHiddenRectIds.get(rectId) === RectShowState.SHOW;
139  }
140
141  function makeRect(id: string, isVisible: boolean, isDisplay = false) {
142    return new UiRectBuilder()
143      .setX(0)
144      .setY(0)
145      .setWidth(1)
146      .setHeight(1)
147      .setLabel(id)
148      .setTransform({
149        dsdx: 1,
150        dsdy: 0,
151        dtdx: 0,
152        dtdy: 1,
153        tx: 0,
154        ty: 0,
155      })
156      .setIsVisible(isVisible)
157      .setIsDisplay(isDisplay)
158      .setId(id)
159      .setGroupId(0)
160      .setIsVirtual(false)
161      .setIsClickable(false)
162      .setCornerRadius(0)
163      .setDepth(0)
164      .setOpacity(0.5)
165      .build();
166  }
167});
168