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