• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 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 {Vector2D, Rect2D, Bounds2D} from './geom';
16
17describe('Vector2D', () => {
18  test('add', () => {
19    const vector1 = new Vector2D({x: 1, y: 2});
20    const vector2 = new Vector2D({x: 3, y: 4});
21    const result = vector1.add(vector2);
22    expect(result.x).toBe(4);
23    expect(result.y).toBe(6);
24  });
25
26  test('sub', () => {
27    const vector1 = new Vector2D({x: 5, y: 7});
28    const vector2 = new Vector2D({x: 2, y: 3});
29    const result = vector1.sub(vector2);
30    expect(result.x).toBe(3);
31    expect(result.y).toBe(4);
32  });
33
34  test('scale', () => {
35    const vector = new Vector2D({x: 2, y: 3});
36    const result = vector.scale(2);
37    expect(result.x).toBe(4);
38    expect(result.y).toBe(6);
39  });
40});
41
42describe('Rect2D', () => {
43  test('asPoint', () => {
44    const rect = new Rect2D({left: 1, top: 2, right: 3, bottom: 4});
45    expect(rect).toMatchObject({x: 1, y: 2});
46  });
47
48  test('asSize', () => {
49    const rect = new Rect2D({left: 1, top: 2, right: 3, bottom: 8});
50    expect(rect).toMatchObject({width: 2, height: 6});
51  });
52
53  test('intersect', () => {
54    const a = new Rect2D({left: 1, top: 1, right: 4, bottom: 4});
55    const b = {left: 2, top: 2, right: 5, bottom: 5};
56    const result = a.intersect(b);
57    expect(result).toMatchObject({left: 2, top: 2, right: 4, bottom: 4});
58    // Note: Non-overlapping rects are UB and thus not tested
59    // TODO(stevegolton): Work out what to do here.
60  });
61
62  test('expand', () => {
63    const rect = new Rect2D({left: 1, top: 1, right: 3, bottom: 3});
64    const result = rect.expand(1);
65    expect(result).toMatchObject({left: 0, top: 0, right: 4, bottom: 4});
66  });
67
68  test('expand 2d', () => {
69    const rect = new Rect2D({left: 1, top: 1, right: 3, bottom: 3});
70    const result = rect.expand({width: 1, height: 2});
71    expect(result).toMatchObject({left: 0, top: -1, right: 4, bottom: 5});
72  });
73
74  test('reframe', () => {
75    const rect = new Rect2D({left: 2, top: 2, right: 5, bottom: 5});
76    const result = rect.reframe({x: 1, y: 1});
77    expect(result).toMatchObject({left: 1, top: 1, right: 4, bottom: 4});
78  });
79
80  test('size', () => {
81    const rect = new Rect2D({left: 1, top: 1, right: 4, bottom: 3});
82    expect(rect).toMatchObject({width: 3, height: 2});
83  });
84
85  it('translate', () => {
86    const rect = new Rect2D({left: 2, top: 2, right: 5, bottom: 5});
87    const result = rect.translate({x: 3, y: 4});
88    expect(result).toMatchObject({left: 5, top: 6, right: 8, bottom: 9});
89  });
90
91  it('contains', () => {
92    const outerRect = new Rect2D({left: 0, top: 0, right: 10, bottom: 10});
93    const innerRect: Bounds2D = {left: 2, top: 2, right: 8, bottom: 8};
94    expect(outerRect.contains(innerRect)).toBe(true);
95
96    const nonContainedRect: Bounds2D = {left: 2, top: 2, right: 12, bottom: 8};
97    expect(outerRect.contains(nonContainedRect)).toBe(false);
98  });
99
100  test('fromPointAndSize', () => {
101    const rect = Rect2D.fromPointAndSize({
102      x: 10,
103      y: 20,
104      width: 100,
105      height: 50,
106    });
107
108    expect(rect.left).toBe(10);
109    expect(rect.top).toBe(20);
110    expect(rect.right).toBe(110);
111    expect(rect.bottom).toBe(70);
112    expect(rect.width).toBe(100);
113    expect(rect.height).toBe(50);
114  });
115
116  test('fromPoints', () => {
117    const rect = Rect2D.fromPoints({x: 0, y: 0}, {x: 100, y: 100});
118
119    expect(rect.left).toBe(0);
120    expect(rect.top).toBe(0);
121    expect(rect.right).toBe(100);
122    expect(rect.bottom).toBe(100);
123  });
124
125  test('fromPoints reversed', () => {
126    const rect = Rect2D.fromPoints({x: 100, y: 100}, {x: 0, y: 0});
127
128    expect(rect.left).toBe(0);
129    expect(rect.top).toBe(0);
130    expect(rect.right).toBe(100);
131    expect(rect.bottom).toBe(100);
132  });
133
134  describe('containsPoint', () => {
135    let rect: Rect2D;
136
137    beforeEach(() => {
138      rect = new Rect2D({left: 10, top: 20, right: 110, bottom: 70});
139    });
140
141    test('inside the rectangle', () => {
142      expect(rect.containsPoint({x: 50, y: 50})).toBe(true);
143    });
144
145    test('outside the rectangle', () => {
146      expect(rect.containsPoint({x: 5, y: 50})).toBe(false); // Left of rect
147      expect(rect.containsPoint({x: 50, y: 75})).toBe(false); // Below rect
148      expect(rect.containsPoint({x: 150, y: 50})).toBe(false); // Right of rect
149      expect(rect.containsPoint({x: 50, y: 15})).toBe(false); // Above rect
150    });
151
152    test('boundary case', () => {
153      expect(rect.containsPoint({x: 10, y: 20})).toBe(true); // Top-left corner
154      expect(rect.containsPoint({x: 110, y: 20})).toBe(false); // On right edge
155      expect(rect.containsPoint({x: 10, y: 70})).toBe(false); // On bottom edge
156    });
157  });
158});
159