1/*
2	$Id: RegionTestcase.cpp 7533 2004-05-12 06:37:18Z jackburton $
3
4	This file implements a base class for all tests of the Haiku
5	BRegion code.
6
7	*/
8
9
10#include "RegionTestcase.h"
11#include <Region.h>
12#include <Rect.h>
13
14#include <assert.h>
15#include <math.h>
16
17
18/*
19 *  Method:  RegionTestcase::RegionTestcase()
20 *   Descr:  This is the constructor for this class.
21 */
22
23RegionTestcase::RegionTestcase(std::string name) :
24	TestCase(name)
25{
26	const int numRectsPerRegion = 3;
27
28	float theRegions[][numRectsPerRegion][4] =
29		{
30			{
31				{10.0, 10.0, 50.0, 50.0},
32				{25.0, 10.0, 75.0, 40.0},
33				{70.0, 100.0, 90.0, 120.0}
34			},
35			{
36				{15.0, 15.0, 45.0, 45.0},
37				{30.0, 15.0, 70.0, 35.0},
38				{75.0, 105.0, 85.0, 115.0}
39			},
40			{
41				{15.0, 15.0, 55.0, 55.0},
42				{30.0, 15.0, 80.0, 45.0},
43				{75.0, 105.0, 95.0, 125.0}
44			},
45			{
46				{210.0, 210.0, 250.0, 250.0},
47				{225.0, 210.0, 275.0, 240.0},
48				{270.0, 300.0, 290.0, 320.0}
49			},
50			{
51				{-50.0, -50.0, -10.0, -10.0},
52				{-75.0, -40.0, -25.0, -10.0},
53				{-90.0, -120.0, -70.0, -100.0}
54			},
55			{
56				{-50.0, -30.0, 100.0, 120.0},
57				{-140.0, 120.0, 340.0, 905.0},
58				{-90.0, -120.0, 90.0, 120.0}
59			},
60			{
61				// A test to see if our BRegion can handle non integers
62				// rects coordinates (as R5 do)
63				{10.3, 10.8, 50.2, 50.9},
64				{25.1, 10.7, 75.8, 40.4},
65				{70.6, 100.6, 90.1, 120.3}
66			},
67			{
68				{15.0, 25.0, 75.0, 80.0},
69				{30.0, 15.0, 80.0, 45.0},
70				{60.0, 20.0, 95.0, 225.0}
71			},
72			// These two regions were added to test our implementation
73			// against the "Pahtz matrix test" (see interface kit
74			// mailing list archives (April 2004) for more info)
75			{
76				{0.0, 50.0, 47.0, 50.0},
77				{99.0, 50.0, 399.0, 50.0},
78				{-100.0, -20.0, 100.0, -20.0}
79			},
80			{
81				{0.0, 50.0, 47.0, 50.0},
82				{100.0, 50.0, 399.0, 50.0},
83				{-100.0, -20.0, 100.0, -20.0}
84			}
85		};
86
87	const int numTestRegions = sizeof(theRegions) / sizeof(theRegions[0]);
88
89	listOfRegions.AddItem(new BRegion);
90	for(int regionNum = 0; regionNum < numTestRegions; regionNum++) {
91		BRegion *tempRegion = new BRegion;
92		for(int rectNum = 0; rectNum < numRectsPerRegion; rectNum++) {
93			tempRegion->Include(BRect(theRegions[regionNum][rectNum][0],
94			                          theRegions[regionNum][rectNum][1],
95			                          theRegions[regionNum][rectNum][2],
96			                          theRegions[regionNum][rectNum][3]));
97		}
98		listOfRegions.AddItem(tempRegion);
99	}
100}
101
102
103/*
104 *  Method:  RegionTestcase::~RegionTestcase()
105 *   Descr:  This is the destructor for this class.
106 */
107
108RegionTestcase::~RegionTestcase()
109{
110	while(!listOfRegions.IsEmpty()) {
111		delete static_cast<BRegion *>(listOfRegions.RemoveItem(int32(0)));
112	}
113}
114
115
116/*
117 *  Method:  RegionTestcase::GetPointsInRect()
118 *   Descr:  This member function returns an array of BPoints on the edge and
119 *           inside the passed in BRect.  It also returns the number of points
120 *           in the array.
121 */
122
123int RegionTestcase::GetPointsInRect(BRect theRect, BPoint **pointArrayPtr)
124{
125	*pointArrayPtr = pointArray;
126	if (!theRect.IsValid()) {
127		return(0);
128	}
129
130	float xIncrement = (theRect.Width() + 1.0) / (numPointsPerSide - 1);
131	float yIncrement = (theRect.Height() + 1.0) / (numPointsPerSide - 1);
132
133	int numPoints = 0;
134
135	for(int i = 0; i < numPointsPerSide; i++) {
136		float xCoord = theRect.left + (i * xIncrement);
137		if (i == numPointsPerSide - 1) {
138			xCoord = theRect.right;
139		}
140		for(int j = 0; j < numPointsPerSide; j++) {
141			float yCoord = theRect.top + (j * yIncrement);
142			if (j == numPointsPerSide - 1) {
143				yCoord = theRect.bottom;
144			}
145			pointArray[numPoints].Set(floor(xCoord), floor(yCoord));
146			assert(theRect.Contains(pointArray[numPoints]));
147			numPoints++;
148		}
149	}
150	return(numPoints);
151}
152
153
154/*
155 *  Method:  RegionTestcase::CheckFrame()
156 *   Descr:  This member function checks that the BRegion's frame matches
157 *           the regions contents.
158 */
159
160void RegionTestcase::CheckFrame(BRegion *theRegion)
161{
162	BRect theFrame = theRegion->Frame();
163	if (theFrame.IsValid()) {
164		assert(!RegionIsEmpty(theRegion));
165
166		BRect testFrame = theRegion->RectAt(0);
167		assert(theFrame.Contains(testFrame));
168
169		for(int i = 1; i < theRegion->CountRects(); i++) {
170			BRect tempRect = theRegion->RectAt(i);
171			assert(theFrame.Contains(tempRect));
172			testFrame = testFrame | tempRect;
173		}
174		assert(testFrame == theFrame);
175	} else {
176		assert(RegionIsEmpty(theRegion));
177	}
178}
179
180
181/*
182 *  Method:  RegionTestcase::RegionsAreEqual()
183 *   Descr:  This member function returns true if the two BRegion's passed
184 *           in are the same, otherwise it returns false.
185 */
186
187bool RegionTestcase::RegionsAreEqual(BRegion *regionA, BRegion *regionB)
188{
189	bool result = false;
190
191	if (regionA->CountRects() == regionB->CountRects()) {
192		bool gotAMatch = true;
193		for(int i = 0; i < regionA->CountRects(); i++) {
194			gotAMatch = false;
195			for(int j = 0; j < regionB->CountRects(); j++) {
196				if (regionA->RectAt(i) == regionB->RectAt(j)) {
197					gotAMatch = true;
198					break;
199				}
200			}
201			if (!gotAMatch) {
202				break;
203			}
204		}
205		if (gotAMatch) {
206			result = true;
207		}
208	}
209
210	if (!result) {
211		BRegion tempRegion(*regionA);
212
213		tempRegion.Exclude(regionB);
214		if (RegionIsEmpty(&tempRegion)) {
215			tempRegion = *regionB;
216			tempRegion.Exclude(regionA);
217			if (RegionIsEmpty(&tempRegion)) {
218				result = true;
219			}
220		}
221	}
222
223	if (result) {
224		assert(regionA->Frame() == regionB->Frame());
225		if (regionA->CountRects() == 0) {
226			assert(RegionIsEmpty(regionA));
227			assert(RegionIsEmpty(regionB));
228		}
229	}
230	return(result);
231}
232
233
234/*
235 *  Method:  RegionTestcase::RegionsIsEmpty()
236 *   Descr:  This member function returns true if the BRegion passed
237 *           in is an empty region, otherwise it returns false.
238 */
239
240bool RegionTestcase::RegionIsEmpty(BRegion *theRegion)
241{
242	if (theRegion->CountRects() == 0) {
243		assert(!theRegion->Frame().IsValid());
244		return(true);
245	}
246	assert(theRegion->Frame().IsValid());
247	return(false);
248}
249
250
251/*
252 *  Method:  RegionTestcase::PerformTest()
253 *   Descr:  This member function iterates over the set of BRegion's for
254 *           testing and calls testOneRegion() for each region.  Then it
255 *           calls testTwoRegions() for each pair of regions (including
256 *           when the two regions are the same).
257 */
258
259void RegionTestcase::PerformTest(void)
260{
261	int numItems = listOfRegions.CountItems();
262
263	for(int i = 0; i < numItems; i++) {
264		BRegion *testRegion = static_cast<BRegion *>(listOfRegions.ItemAt(i));
265
266		CheckFrame(testRegion);
267		testOneRegion(testRegion);
268	}
269	for(int i = 0; i < numItems; i++) {
270		BRegion *testRegionA = static_cast<BRegion *>(listOfRegions.ItemAt(i));
271
272		for(int j = 0; j < numItems; j++) {
273			BRegion *testRegionB = static_cast<BRegion *>(listOfRegions.ItemAt(j));
274
275			testTwoRegions(testRegionA, testRegionB);
276		}
277	}
278}
279