1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package image
6
7import (
8	"fmt"
9	"testing"
10)
11
12func TestRectangle(t *testing.T) {
13	// in checks that every point in f is in g.
14	in := func(f, g Rectangle) error {
15		if !f.In(g) {
16			return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g)
17		}
18		for y := f.Min.Y; y < f.Max.Y; y++ {
19			for x := f.Min.X; x < f.Max.X; x++ {
20				p := Point{x, y}
21				if !p.In(g) {
22					return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g)
23				}
24			}
25		}
26		return nil
27	}
28
29	rects := []Rectangle{
30		Rect(0, 0, 10, 10),
31		Rect(10, 0, 20, 10),
32		Rect(1, 2, 3, 4),
33		Rect(4, 6, 10, 10),
34		Rect(2, 3, 12, 5),
35		Rect(-1, -2, 0, 0),
36		Rect(-1, -2, 4, 6),
37		Rect(-10, -20, 30, 40),
38		Rect(8, 8, 8, 8),
39		Rect(88, 88, 88, 88),
40		Rect(6, 5, 4, 3),
41	}
42
43	// r.Eq(s) should be equivalent to every point in r being in s, and every
44	// point in s being in r.
45	for _, r := range rects {
46		for _, s := range rects {
47			got := r.Eq(s)
48			want := in(r, s) == nil && in(s, r) == nil
49			if got != want {
50				t.Errorf("Eq: r=%s, s=%s: got %t, want %t", r, s, got, want)
51			}
52		}
53	}
54
55	// The intersection should be the largest rectangle a such that every point
56	// in a is both in r and in s.
57	for _, r := range rects {
58		for _, s := range rects {
59			a := r.Intersect(s)
60			if err := in(a, r); err != nil {
61				t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err)
62			}
63			if err := in(a, s); err != nil {
64				t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err)
65			}
66			if isZero, overlaps := a == (Rectangle{}), r.Overlaps(s); isZero == overlaps {
67				t.Errorf("Intersect: r=%s, s=%s, a=%s: isZero=%t same as overlaps=%t",
68					r, s, a, isZero, overlaps)
69			}
70			largerThanA := [4]Rectangle{a, a, a, a}
71			largerThanA[0].Min.X--
72			largerThanA[1].Min.Y--
73			largerThanA[2].Max.X++
74			largerThanA[3].Max.Y++
75			for i, b := range largerThanA {
76				if b.Empty() {
77					// b isn't actually larger than a.
78					continue
79				}
80				if in(b, r) == nil && in(b, s) == nil {
81					t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger",
82						r, s, a, b, i)
83				}
84			}
85		}
86	}
87
88	// The union should be the smallest rectangle a such that every point in r
89	// is in a and every point in s is in a.
90	for _, r := range rects {
91		for _, s := range rects {
92			a := r.Union(s)
93			if err := in(r, a); err != nil {
94				t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err)
95			}
96			if err := in(s, a); err != nil {
97				t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err)
98			}
99			if a.Empty() {
100				// You can't get any smaller than a.
101				continue
102			}
103			smallerThanA := [4]Rectangle{a, a, a, a}
104			smallerThanA[0].Min.X++
105			smallerThanA[1].Min.Y++
106			smallerThanA[2].Max.X--
107			smallerThanA[3].Max.Y--
108			for i, b := range smallerThanA {
109				if in(r, b) == nil && in(s, b) == nil {
110					t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller",
111						r, s, a, b, i)
112				}
113			}
114		}
115	}
116}
117