import { Box } from './Box'
import { Vec } from './Vec'

describe('Box', () => {
	let box: Box

	beforeEach(() => {
		box = new Box(10, 20, 100, 200)
	})

	it('Creates a box', () => {
		const newBox = new Box(0, 0, 100, 100)
		expect(newBox).toMatchObject({
			x: 0,
			y: 0,
			w: 100,
			h: 100,
		})
	})

	describe('Box.point', () => {
		it('gets the point as a Vec', () => {
			expect(box.point).toEqual(new Vec(10, 20))
		})

		it('sets the point with a Vec', () => {
			box.point = new Vec(50, 60)
			expect(box.x).toBe(50)
			expect(box.y).toBe(60)
		})
	})

	describe('Box.minX', () => {
		it('gets the minimum X value', () => {
			expect(box.minX).toBe(10)
		})

		it('sets the minimum X value', () => {
			box.minX = 30
			expect(box.x).toBe(30)
		})
	})

	describe('Box.left', () => {
		it('gets the left edge', () => {
			expect(box.left).toBe(10)
		})
	})

	describe('Box.midX', () => {
		it('gets the middle X value', () => {
			expect(box.midX).toBe(60) // 10 + 100/2
		})
	})

	describe('Box.maxX', () => {
		it('gets the maximum X value', () => {
			expect(box.maxX).toBe(110) // 10 + 100
		})
	})

	describe('Box.right', () => {
		it('gets the right edge', () => {
			expect(box.right).toBe(110) // 10 + 100
		})
	})

	describe('Box.minY', () => {
		it('gets the minimum Y value', () => {
			expect(box.minY).toBe(20)
		})

		it('sets the minimum Y value', () => {
			box.minY = 40
			expect(box.y).toBe(40)
		})
	})

	describe('Box.top', () => {
		it('gets the top edge', () => {
			expect(box.top).toBe(20)
		})
	})

	describe('Box.midY', () => {
		it('gets the middle Y value', () => {
			expect(box.midY).toBe(120) // 20 + 200/2
		})
	})

	describe('Box.maxY', () => {
		it('gets the maximum Y value', () => {
			expect(box.maxY).toBe(220) // 20 + 200
		})
	})

	describe('Box.bottom', () => {
		it('gets the bottom edge', () => {
			expect(box.bottom).toBe(220) // 20 + 200
		})
	})

	describe('Box.width', () => {
		it('gets the width', () => {
			expect(box.width).toBe(100)
		})

		it('sets the width', () => {
			box.width = 150
			expect(box.w).toBe(150)
		})
	})

	describe('Box.height', () => {
		it('gets the height', () => {
			expect(box.height).toBe(200)
		})

		it('sets the height', () => {
			box.height = 250
			expect(box.h).toBe(250)
		})
	})

	describe('Box.aspectRatio', () => {
		it('gets the aspect ratio', () => {
			expect(box.aspectRatio).toBe(0.5) // 100/200
		})
	})

	describe('Box.center', () => {
		it('gets the center point', () => {
			expect(box.center).toEqual(new Vec(60, 120))
		})

		it('sets the center point', () => {
			box.center = new Vec(100, 150)
			expect(box.x).toBe(50) // 100 - 100/2
			expect(box.y).toBe(50) // 150 - 200/2
		})
	})

	describe('Box.corners', () => {
		it('gets the corners', () => {
			const corners = box.corners
			expect(corners).toEqual([
				new Vec(10, 20), // top-left
				new Vec(110, 20), // top-right (fixed from buggy bottom-right)
				new Vec(110, 220), // bottom-right
				new Vec(10, 220), // bottom-left
			])
		})
	})

	describe('Box.cornersAndCenter', () => {
		it('gets the corners and center', () => {
			const cornersAndCenter = box.cornersAndCenter
			expect(cornersAndCenter).toEqual([
				new Vec(10, 20), // top-left
				new Vec(110, 20), // top-right (fixed from buggy bottom-right)
				new Vec(110, 220), // bottom-right
				new Vec(10, 220), // bottom-left
				new Vec(60, 120), // center
			])
		})
	})

	describe('Box.sides', () => {
		it('gets the sides as pairs of vectors', () => {
			const sides = box.sides
			const corners = box.corners
			expect(sides).toEqual([
				[corners[0], corners[1]],
				[corners[1], corners[2]],
				[corners[2], corners[3]],
				[corners[3], corners[0]],
			])
		})
	})

	describe('Box.size', () => {
		it('gets the size as a Vec', () => {
			expect(box.size).toEqual(new Vec(100, 200))
		})
	})

	describe('Box.toFixed', () => {
		it('applies precision to all values', () => {
			const impreciseBox = new Box(10.123456789, 20.987654321, 100.555555, 200.777777)
			const result = impreciseBox.toFixed()
			expect(result.x).toBeCloseTo(10.123456789, 6)
			expect(result.y).toBeCloseTo(20.987654321, 6)
			expect(result.w).toBeCloseTo(100.555555, 6)
			expect(result.h).toBeCloseTo(200.777777, 6)
			expect(result).toBe(impreciseBox) // returns self
		})
	})

	describe('Box.setTo', () => {
		it('copies values from another box', () => {
			const otherBox = new Box(50, 60, 150, 250)
			const result = box.setTo(otherBox)
			expect(box.x).toBe(50)
			expect(box.y).toBe(60)
			expect(box.w).toBe(150)
			expect(box.h).toBe(250)
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.set', () => {
		it('sets all values', () => {
			const result = box.set(30, 40, 120, 180)
			expect(box.x).toBe(30)
			expect(box.y).toBe(40)
			expect(box.w).toBe(120)
			expect(box.h).toBe(180)
			expect(result).toBe(box) // returns self
		})

		it('uses default values when no parameters provided', () => {
			const result = box.set()
			expect(box.x).toBe(0)
			expect(box.y).toBe(0)
			expect(box.w).toBe(0)
			expect(box.h).toBe(0)
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.expand', () => {
		it('expands to include another box', () => {
			const otherBox = new Box(5, 15, 120, 240) // overlaps and extends
			const result = box.expand(otherBox)
			expect(box.x).toBe(5) // min of 10 and 5
			expect(box.y).toBe(15) // min of 20 and 15
			expect(box.w).toBe(120) // max(110, 125) - min(10, 5) = 125 - 5
			expect(box.h).toBe(240) // max(220, 255) - min(20, 15) = 255 - 15
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.expandBy', () => {
		it('expands by a given amount', () => {
			const result = box.expandBy(10)
			expect(box.x).toBe(0) // 10 - 10
			expect(box.y).toBe(10) // 20 - 10
			expect(box.w).toBe(120) // 100 + 10*2
			expect(box.h).toBe(220) // 200 + 10*2
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.scale', () => {
		it('scales the box by a factor', () => {
			const result = box.scale(2)
			expect(box.x).toBe(5) // 10/2
			expect(box.y).toBe(10) // 20/2
			expect(box.w).toBe(50) // 100/2
			expect(box.h).toBe(100) // 200/2
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.clone', () => {
		it('creates a copy of the box', () => {
			const cloned = box.clone()
			expect(cloned).toEqual(box)
			expect(cloned).not.toBe(box) // different object
		})
	})

	describe('Box.translate', () => {
		it('translates the box by a delta', () => {
			const delta = new Vec(5, 10)
			const result = box.translate(delta)
			expect(box.x).toBe(15) // 10 + 5
			expect(box.y).toBe(30) // 20 + 10
			expect(box.w).toBe(100) // unchanged
			expect(box.h).toBe(200) // unchanged
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.snapToGrid', () => {
		it('snaps the box to a grid', () => {
			const testBox = new Box(12, 18, 95, 185)
			testBox.snapToGrid(10)
			expect(testBox.minX).toBe(10) // rounded to nearest 10
			expect(testBox.minY).toBe(20) // rounded to nearest 10
			expect(testBox.width).toBe(100) // snapped width
			expect(testBox.height).toBe(180) // snapped height
		})

		it('ensures minimum size of 1', () => {
			const testBox = new Box(0, 0, 3, 3)
			testBox.snapToGrid(10)
			expect(testBox.width).toBe(1) // minimum 1
			expect(testBox.height).toBe(1) // minimum 1
		})
	})

	describe('Box.collides', () => {
		it('returns true when boxes collide', () => {
			const otherBox = new Box(50, 100, 100, 100) // overlaps
			expect(box.collides(otherBox)).toBe(true)
		})

		it('returns false when boxes do not collide', () => {
			const otherBox = new Box(200, 300, 100, 100) // no overlap
			expect(box.collides(otherBox)).toBe(false)
		})
	})

	describe('Box.contains', () => {
		it('returns true when this box contains the other', () => {
			const otherBox = new Box(20, 30, 50, 100) // inside box
			expect(box.contains(otherBox)).toBe(true)
		})

		it('returns false when this box does not contain the other', () => {
			const otherBox = new Box(5, 5, 200, 300) // larger than box
			expect(box.contains(otherBox)).toBe(false)
		})
	})

	describe('Box.includes', () => {
		it('returns true when boxes collide or contain', () => {
			const collidingBox = new Box(50, 100, 100, 100)
			const containedBox = new Box(20, 30, 50, 100)
			expect(box.includes(collidingBox)).toBe(true)
			expect(box.includes(containedBox)).toBe(true)
		})

		it('returns false when boxes do not interact', () => {
			const separateBox = new Box(200, 300, 100, 100)
			expect(box.includes(separateBox)).toBe(false)
		})
	})

	describe('Box.containsPoint', () => {
		it('returns true when point is inside', () => {
			const point = new Vec(50, 100)
			expect(box.containsPoint(point)).toBe(true)
		})

		it('returns false when point is outside', () => {
			const point = new Vec(150, 300)
			expect(box.containsPoint(point)).toBe(false)
		})

		it('respects margin', () => {
			const point = new Vec(5, 15) // just outside
			expect(box.containsPoint(point)).toBe(false)
			expect(box.containsPoint(point, 10)).toBe(true) // with margin
		})
	})

	describe('Box.getHandlePoint', () => {
		it('returns correct points for corners', () => {
			expect(box.getHandlePoint('top_left')).toEqual(new Vec(10, 20))
			expect(box.getHandlePoint('top_right')).toEqual(new Vec(110, 20))
			expect(box.getHandlePoint('bottom_left')).toEqual(new Vec(10, 220))
			expect(box.getHandlePoint('bottom_right')).toEqual(new Vec(110, 220))
		})

		it('returns correct points for edges', () => {
			expect(box.getHandlePoint('top')).toEqual(new Vec(60, 20))
			expect(box.getHandlePoint('right')).toEqual(new Vec(110, 120))
			expect(box.getHandlePoint('bottom')).toEqual(new Vec(60, 220))
			expect(box.getHandlePoint('left')).toEqual(new Vec(10, 120))
		})
	})

	describe('Box.toJson', () => {
		it('returns box model object', () => {
			expect(box.toJson()).toEqual({
				x: 10,
				y: 20,
				w: 100,
				h: 200,
			})
		})
	})

	describe('Box.resize', () => {
		it('resizes from top-left handle', () => {
			box.resize('top_left', 10, 20)
			expect(box.minX).toBe(20) // moved right
			expect(box.minY).toBe(40) // moved down
			expect(box.width).toBe(90) // reduced width
			expect(box.height).toBe(180) // reduced height
		})

		it('resizes from bottom-right handle', () => {
			box.resize('bottom_right', 10, 20)
			expect(box.minX).toBe(10) // unchanged
			expect(box.minY).toBe(20) // unchanged
			expect(box.width).toBe(110) // increased width
			expect(box.height).toBe(220) // increased height
		})
	})

	describe('Box.union', () => {
		it('creates union with another box', () => {
			const otherBox = { x: 5, y: 15, w: 120, h: 240 }
			const result = box.union(otherBox)
			expect(box.x).toBe(5)
			expect(box.y).toBe(15)
			expect(box.width).toBe(120) // max(110, 125) - min(10, 5)
			expect(box.height).toBe(240) // max(220, 255) - min(20, 15)
			expect(result).toBe(box) // returns self
		})
	})

	describe('Box.equals', () => {
		it('returns true for equal boxes', () => {
			const otherBox = new Box(10, 20, 100, 200)
			expect(box.equals(otherBox)).toBe(true)
		})

		it('returns false for different boxes', () => {
			const otherBox = new Box(10, 20, 100, 201)
			expect(box.equals(otherBox)).toBe(false)
		})
	})

	describe('Box.zeroFix', () => {
		it('ensures minimum size of 1', () => {
			const zeroBox = new Box(0, 0, 0, 0)
			const result = zeroBox.zeroFix()
			expect(zeroBox.w).toBe(1)
			expect(zeroBox.h).toBe(1)
			expect(result).toBe(zeroBox) // returns self
		})
	})

	// Static method tests
	describe('Box.From', () => {
		it('creates box from box model', () => {
			const boxModel = { x: 5, y: 10, w: 50, h: 100 }
			const result = Box.From(boxModel)
			expect(result).toEqual(new Box(5, 10, 50, 100))
		})
	})

	describe('Box.FromCenter', () => {
		it('creates box from center and size', () => {
			const center = new Vec(50, 100)
			const size = new Vec(20, 40)
			const result = Box.FromCenter(center, size)
			expect(result).toEqual(new Box(40, 80, 20, 40))
		})
	})

	describe('Box.FromPoints', () => {
		it('creates box from array of points', () => {
			const points = [new Vec(10, 20), new Vec(110, 220), new Vec(50, 100)]
			const result = Box.FromPoints(points)
			expect(result).toEqual(new Box(10, 20, 100, 200))
		})

		it('returns empty box for empty array', () => {
			const result = Box.FromPoints([])
			expect(result).toEqual(new Box())
		})
	})

	describe('Box.Expand', () => {
		it('creates expanded box from two boxes', () => {
			const boxA = new Box(10, 20, 100, 200)
			const boxB = new Box(5, 15, 120, 240)
			const result = Box.Expand(boxA, boxB)
			expect(result).toEqual(new Box(5, 15, 120, 240))
		})
	})

	describe('Box.ExpandBy', () => {
		it('creates expanded box by amount', () => {
			const result = Box.ExpandBy(box, 10)
			expect(result).toEqual(new Box(0, 10, 120, 220))
		})
	})

	describe('Box.Collides', () => {
		it('returns true when boxes collide', () => {
			const boxA = new Box(0, 0, 50, 50)
			const boxB = new Box(25, 25, 50, 50)
			expect(Box.Collides(boxA, boxB)).toBe(true)
		})

		it('returns false when boxes do not collide', () => {
			const boxA = new Box(0, 0, 50, 50)
			const boxB = new Box(100, 100, 50, 50)
			expect(Box.Collides(boxA, boxB)).toBe(false)
		})
	})

	describe('Box.Contains', () => {
		it('returns true when first box contains second', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(10, 10, 50, 50)
			expect(Box.Contains(boxA, boxB)).toBe(true)
		})

		it('returns false when first box does not contain second', () => {
			const boxA = new Box(0, 0, 50, 50)
			const boxB = new Box(10, 10, 100, 100)
			expect(Box.Contains(boxA, boxB)).toBe(false)
		})
	})

	describe('Box.ContainsApproximately', () => {
		it('returns true when first box exactly contains second', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(10, 10, 50, 50)
			expect(Box.ContainsApproximately(boxA, boxB)).toBe(true)
		})

		it('returns false when first box clearly does not contain second', () => {
			const boxA = new Box(0, 0, 50, 50)
			const boxB = new Box(10, 10, 100, 100)
			expect(Box.ContainsApproximately(boxA, boxB)).toBe(false)
		})

		it('returns true when containment is within default precision tolerance', () => {
			// Box B extends very slightly outside A (within floating-point precision)
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(10, 10, 80, 80)
			// Move B's max edges just slightly outside A's bounds
			boxB.w = 90.000000000001 // maxX = 100.000000000001 (slightly beyond 100)
			boxB.h = 90.000000000001 // maxY = 100.000000000001 (slightly beyond 100)

			expect(Box.ContainsApproximately(boxA, boxB)).toBe(true)
			expect(Box.Contains(boxA, boxB)).toBe(false) // strict contains would fail
		})

		it('returns false when containment exceeds default precision tolerance', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(10, 10, 80, 80)
			// Move B's max edges clearly outside A's bounds
			boxB.w = 95 // maxX = 105 (clearly beyond 100)
			boxB.h = 95 // maxY = 105 (clearly beyond 100)

			expect(Box.ContainsApproximately(boxA, boxB)).toBe(false)
		})

		it('respects custom precision parameter', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(10, 10, 85, 85) // maxX=95, maxY=95

			// With loose precision (10), should contain (95 is within 100-10=90 tolerance)
			expect(Box.ContainsApproximately(boxA, boxB, 10)).toBe(true)

			// With tight precision (4), should still contain (95 is within 100-4=96)
			expect(Box.ContainsApproximately(boxA, boxB, 4)).toBe(true)

			// Since 95 < 100, the precision parameter doesn't affect containment here
			expect(Box.ContainsApproximately(boxA, boxB, 4.9)).toBe(true)
		})

		it('handles negative coordinates correctly', () => {
			const boxA = new Box(-50, -50, 100, 100) // bounds: (-50,-50) to (50,50)
			const boxB = new Box(-40, -40, 79.999999999, 79.999999999) // bounds: (-40,-40) to (39.999999999, 39.999999999)

			expect(Box.ContainsApproximately(boxA, boxB)).toBe(true)
		})

		it('handles edge case where boxes are identical', () => {
			const boxA = new Box(10, 20, 100, 200)
			const boxB = new Box(10, 20, 100, 200)

			expect(Box.ContainsApproximately(boxA, boxB)).toBe(true)
		})

		it('handles edge case where inner box touches outer box edges', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(0, 0, 100, 100) // exactly the same

			expect(Box.ContainsApproximately(boxA, boxB)).toBe(true)

			// Slightly smaller inner box
			const boxC = new Box(0.000001, 0.000001, 99.999998, 99.999998)
			expect(Box.ContainsApproximately(boxA, boxC)).toBe(true)
		})

		it('handles floating-point precision issues in real-world scenarios', () => {
			// Simulate common floating-point arithmetic issues
			const containerBox = new Box(0, 0, 100, 100)

			// Box that should be contained but has floating-point errors
			const innerBox = new Box(10, 10, 80, 80)
			// Simulate floating-point arithmetic that results in tiny overruns
			innerBox.w = 90.00000000000001 // maxX = 100.00000000000001 (tiny overrun)
			innerBox.h = 90.00000000000001 // maxY = 100.00000000000001 (tiny overrun)

			expect(Box.ContainsApproximately(containerBox, innerBox)).toBe(true)
			expect(Box.Contains(containerBox, innerBox)).toBe(false) // strict contains fails due to precision
		})

		it('fails when any edge exceeds tolerance', () => {
			const boxA = new Box(10, 10, 100, 100) // bounds: (10,10) to (110,110)

			// Test each edge exceeding tolerance
			const testCases = [
				{ name: 'left edge', box: new Box(5, 20, 80, 80) }, // minX too small
				{ name: 'top edge', box: new Box(20, 5, 80, 80) }, // minY too small
				{ name: 'right edge', box: new Box(20, 20, 95, 80) }, // maxX too large (20+95=115 > 110)
				{ name: 'bottom edge', box: new Box(20, 20, 80, 95) }, // maxY too large (20+95=115 > 110)
			]

			testCases.forEach(({ box }) => {
				expect(Box.ContainsApproximately(boxA, box, 1)).toBe(false) // tight precision
			})
		})

		it('works with zero-sized dimensions', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(50, 50, 0, 0) // zero-sized box (point)

			expect(Box.ContainsApproximately(boxA, boxB)).toBe(true)
		})

		it('handles precision parameter edge cases', () => {
			const boxA = new Box(0, 0, 100, 100)
			const boxB = new Box(10, 10, 91, 91) // maxX=101, maxY=101 (clearly outside)

			// Zero precision should work like strict Contains
			expect(Box.ContainsApproximately(boxA, boxB, 0)).toBe(false)

			// Small precision should still fail (101 > 100)
			expect(Box.ContainsApproximately(boxA, boxB, 0.5)).toBe(false)

			// Sufficient precision should succeed (101 <= 100 + 2)
			expect(Box.ContainsApproximately(boxA, boxB, 2)).toBe(true)
		})
	})

	describe('Box.Includes', () => {
		it('returns true when boxes collide or contain', () => {
			const boxA = new Box(0, 0, 50, 50)
			const boxB = new Box(25, 25, 50, 50) // colliding
			const boxC = new Box(10, 10, 20, 20) // contained
			expect(Box.Includes(boxA, boxB)).toBe(true)
			expect(Box.Includes(boxA, boxC)).toBe(true)
		})

		it('returns false when boxes do not interact', () => {
			const boxA = new Box(0, 0, 50, 50)
			const boxB = new Box(100, 100, 50, 50)
			expect(Box.Includes(boxA, boxB)).toBe(false)
		})
	})

	describe('Box.ContainsPoint', () => {
		it('returns true when point is inside box', () => {
			const testBox = new Box(0, 0, 100, 100)
			const point = new Vec(50, 50)
			expect(Box.ContainsPoint(testBox, point)).toBe(true)
		})

		it('returns false when point is outside box', () => {
			const testBox = new Box(0, 0, 100, 100)
			const point = new Vec(150, 150)
			expect(Box.ContainsPoint(testBox, point)).toBe(false)
		})

		it('respects margin parameter', () => {
			const testBox = new Box(0, 0, 100, 100)
			const point = new Vec(-5, -5)
			expect(Box.ContainsPoint(testBox, point)).toBe(false)
			expect(Box.ContainsPoint(testBox, point, 10)).toBe(true)
		})
	})

	describe('Box.Common', () => {
		it('creates bounding box of multiple boxes', () => {
			const boxes = [new Box(0, 0, 50, 50), new Box(75, 75, 50, 50), new Box(25, 25, 50, 50)]
			const result = Box.Common(boxes)
			expect(result).toEqual(new Box(0, 0, 125, 125))
		})
	})

	describe('Box.Sides', () => {
		it('returns sides as corner pairs', () => {
			const testBox = new Box(0, 0, 100, 100)
			const sides = Box.Sides(testBox)
			expect(sides).toHaveLength(4)
			expect(sides[0]).toEqual([new Vec(0, 0), new Vec(100, 0)])
		})
	})

	describe('Box.Resize', () => {
		it('resizes box and returns scaling info', () => {
			const testBox = new Box(0, 0, 100, 100)
			const result = Box.Resize(testBox, 'bottom_right', 50, 50)
			expect(result.box).toEqual(new Box(0, 0, 150, 150))
			expect(result.scaleX).toBe(1.5)
			expect(result.scaleY).toBe(1.5)
		})

		it('handles aspect ratio locking', () => {
			const testBox = new Box(0, 0, 100, 100)
			const result = Box.Resize(testBox, 'bottom_right', 50, 25, true)
			expect(result.box.width).toBeCloseTo(result.box.height) // maintains aspect ratio
		})
	})

	describe('Box.Equals', () => {
		it('returns true for equal boxes', () => {
			const boxA = new Box(10, 20, 100, 200)
			const boxB = new Box(10, 20, 100, 200)
			expect(Box.Equals(boxA, boxB)).toBe(true)
		})

		it('returns false for different boxes', () => {
			const boxA = new Box(10, 20, 100, 200)
			const boxB = new Box(10, 20, 100, 201)
			expect(Box.Equals(boxA, boxB)).toBe(false)
		})
	})

	describe('Box.ZeroFix', () => {
		it('creates new box with minimum size of 1', () => {
			const zeroBox = new Box(0, 0, 0, 0)
			const result = Box.ZeroFix(zeroBox)
			expect(result).toEqual(new Box(0, 0, 1, 1))
			expect(result).not.toBe(zeroBox) // different object
		})
	})

	describe('Box.isValid', () => {
		it('returns true for normal box', () => {
			expect(new Box(10, 20, 100, 200).isValid()).toBe(true)
		})

		it('returns false when x is NaN', () => {
			expect(new Box(NaN, 0, 100, 100).isValid()).toBe(false)
		})

		it('returns false when y is NaN', () => {
			expect(new Box(0, NaN, 100, 100).isValid()).toBe(false)
		})

		it('returns false when w is NaN', () => {
			expect(new Box(0, 0, NaN, 100).isValid()).toBe(false)
		})

		it('returns false when h is NaN', () => {
			expect(new Box(0, 0, 100, NaN).isValid()).toBe(false)
		})

		it('returns false for Infinity', () => {
			expect(new Box(Infinity, 0, 100, 100).isValid()).toBe(false)
		})

		it('returns true for zero-sized box', () => {
			expect(new Box(0, 0, 0, 0).isValid()).toBe(true)
		})
	})
})
