text: /**
   * FreeRDP: A Remote Desktop Protocol Implementation
   *
   * Copyright 2014 Thincast Technologies GmbH
   * Copyright 2014 Hardening <contact@hardening-consulting.com>
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #include <winpr/crt.h>
  #include <winpr/print.h>
  
  #include <freerdp/codec/region.h>
  
  
  static BOOL compareRectangles(const RECTANGLE_16* src1, const RECTANGLE_16* src2, int nb)
  {
  	int i;
  
  	for (i = 0; i < nb; i++, src1++, src2++)
  	{
  		if (memcmp(src1, src2, sizeof(RECTANGLE_16)))
  		{
  			fprintf(stderr,
  			        "expecting rect %d (%"PRIu16",%"PRIu16"-%"PRIu16",%"PRIu16") and have (%"PRIu16",%"PRIu16"-%"PRIu16",%"PRIu16")\n",
  			        i, src2->left, src2->top, src2->right, src2->bottom,
  			        src1->left, src1->top, src1->right, src1->bottom
  			       );
  			return FALSE;
  		}
  	}
  
  	return TRUE;
  }
  
  
  static int test_basic(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	/* R1 + R2 ==> disjointed rects */
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r2 = {150, 301, 250, 401};
  	RECTANGLE_16 r1_r2[] =
  	{
  		{0,   101, 200, 201},
  		{150, 301, 250, 401}
  	};
  	/* r1 */
  	region16_init(&region);
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 1 || memcmp(rects, &r1, sizeof(RECTANGLE_16)))
  		goto out;
  
  	/* r1 + r2 */
  	if (!region16_union_rect(&region, &region, &r2))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 2 || !compareRectangles(rects, r1_r2, nbRects))
  		goto out;
  
  	/* clear region */
  	region16_clear(&region);
  	region16_rects(&region, &nbRects);
  
  	if (nbRects)
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_r1_r3(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r3 = {150, 151, 250, 251};
  	RECTANGLE_16 r1_r3[] =
  	{
  		{  0, 101, 200, 151},
  		{  0, 151, 250, 201},
  		{150, 201, 250, 251}
  	};
  	region16_init(&region);
  	/*
  	 * +===============================================================
  	 * |
  	 * |+-----+                +-----+
  	 * || r1  |                |     |
  	 * ||   +-+------+         +-----+--------+
  	 * ||   |    r3  |         |              |
  	 * |+---+        | ====>   +-----+--------+
  	 * |    |        |               |        |
  	 * |    +--------+               +--------+
  	 */
  
  	/* R1 + R3  */
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r3))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r3, nbRects))
  		goto out;
  
  	/* R3 + R1  */
  	region16_clear(&region);
  
  	if (!region16_union_rect(&region, &region, &r3))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r3, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_r9_r10(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	/*
  	 * +===============================================================
  	 * |
  	 * |   +---+                +---+
  	 * |+--|r10|-+           +--+---+-+
  	 * ||r9|   | |           |        |
  	 * ||  |   | |           |        |
  	 * ||  |   | |  =====>   |        |
  	 * ||  |   | |           |        |
  	 * ||  |   | |           |        |
  	 * |+--|   |-+           +--+---+-+
  	 * |   +---+                +---+
  	 */
  	RECTANGLE_16 r9 = {  0, 100, 400, 200};
  	RECTANGLE_16 r10 = {200,  0, 300, 300};
  	RECTANGLE_16 r9_r10[] =
  	{
  		{200,   0, 300, 100},
  		{  0, 100, 400, 200},
  		{200, 200, 300, 300},
  	};
  	region16_init(&region);
  
  	if (!region16_union_rect(&region, &region, &r9))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r10))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 3 || !compareRectangles(rects, r9_r10, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_r1_r5(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r5 = {150, 121, 300, 131};
  	RECTANGLE_16 r1_r5[] =
  	{
  		{  0, 101, 200, 121},
  		{  0, 121, 300, 131},
  		{  0, 131, 200, 201}
  	};
  	region16_init(&region);
  
  	/*
  	 * +===============================================================
  	 * |
  	 * |+--------+               +--------+
  	 * || r1     |               |        |
  	 * ||     +--+----+          +--------+----+
  	 * ||     |  r5   |  =====>  |             |
  	 * ||     +-------+          +--------+----+
  	 * ||        |               |        |
  	 * |+--------+               +--------+
  	 * |
  	 *
  	 */
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r5))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r5, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  static int test_r1_r6(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r6 = {150, 121, 170, 131};
  	region16_init(&region);
  	/*
  	 * +===============================================================
  	 * |
  	 * |+--------+           +--------+
  	 * || r1     |           |        |
  	 * ||   +--+ |           |        |
  	 * ||   |r6| |  =====>   |        |
  	 * ||   +--+ |           |        |
  	 * ||        |           |        |
  	 * |+--------+           +--------+
  	 * |
  	 */
  	region16_clear(&region);
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r6))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 1 || !compareRectangles(rects, &r1, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_r1_r2_r4(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r2 = {150, 301, 250, 401};
  	RECTANGLE_16 r4 = {150, 251, 250, 301};
  	RECTANGLE_16 r1_r2_r4[] =
  	{
  		{  0, 101, 200, 201},
  		{150, 251, 250, 401}
  	};
  	/*
  	 * +===============================================================
  	 * |
  	 * |+-----+                +-----+
  	 * || r1  |                |     |
  	 * ||     |                |     |
  	 * ||     |                |     |
  	 * |+-----+        ====>   +-----+
  	 * |
  	 * |    +--------+               +--------+
  	 * |    |   r4   |               |        |
  	 * |    +--------+               |        |
  	 * |    | r2     |               |        |
  	 * |    |        |               |        |
  	 * |    +--------+               +--------+
  	 *
  	 */
  	region16_init(&region);
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r2))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r4))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 2 || !compareRectangles(rects, r1_r2_r4, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_r1_r7_r8(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r7 = {300, 101, 500, 201};
  	RECTANGLE_16 r8 = {150, 121, 400, 131};
  	RECTANGLE_16 r1_r7_r8[] =
  	{
  		{  0, 101, 200, 121},
  		{300, 101, 500, 121},
  		{  0, 121, 500, 131},
  		{  0, 131, 200, 201},
  		{300, 131, 500, 201},
  	};
  	/*
  	 * +===============================================================
  	 * |
  	 * |+--------+   +--------+           +--------+   +--------+
  	 * || r1     |   | r7     |           |        |   |        |
  	 * ||   +------------+    |           +--------+---+--------+
  	 * ||   |   r8       |    |   =====>  |                     |
  	 * ||   +------------+    |           +--------+---+--------+
  	 * ||        |   |        |           |        |   |        |
  	 * |+--------+   +--------+           +--------+   +--------+
  	 * |
  	 */
  	region16_init(&region);
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r7))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r8))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 5 || !compareRectangles(rects, r1_r7_r8, nbRects))
  		goto out;
  
  	region16_clear(&region);
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r8))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r7))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 5 || !compareRectangles(rects, r1_r7_r8, nbRects))
  		goto out;
  
  	region16_clear(&region);
  
  	if (!region16_union_rect(&region, &region, &r8))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r7))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 5 || !compareRectangles(rects, r1_r7_r8, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_r1_r2_r3_r4(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r2 = {150, 301, 250, 401};
  	RECTANGLE_16 r3 = {150, 151, 250, 251};
  	RECTANGLE_16 r4 = {150, 251, 250, 301};
  	RECTANGLE_16 r1_r2_r3[] =
  	{
  		{  0, 101, 200, 151},
  		{  0, 151, 250, 201},
  		{150, 201, 250, 251},
  		{150, 301, 250, 401}
  	};
  	RECTANGLE_16 r1_r2_r3_r4[] =
  	{
  		{  0, 101, 200, 151},
  		{  0, 151, 250, 201},
  		{150, 201, 250, 401}
  	};
  	region16_init(&region);
  
  	/*
  	 * +===============================================================
  	 * |
  	 * |+-----+                +-----+
  	 * || r1  |                |     |
  	 * ||   +-+------+         +-----+--------+
  	 * ||   |    r3  |         |              |
  	 * |+---+        | ====>   +-----+--------+
  	 * |    |        |               |        |
  	 * |    +--------+               +--------+
  	 * |    +--------+               +--------+
  	 * |    | r2     |               |        |
  	 * |    |        |               |        |
  	 * |    +--------+               +--------+
  	 */
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r2))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r3))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 4 || !compareRectangles(rects, r1_r2_r3, 4))
  		goto out;
  
  	/*
  	 * +===============================================================
  	 * |
  	 * |+-----+                 +-----+
  	 * ||     |                 |     |
  	 * |+-----+--------+        +-----+--------+
  	 * ||              |  ==>   |              |
  	 * |+-----+--------+        +-----+--------+
  	 * |  	  |        |              |        |
  	 * |  	  +--------+              |        |
  	 * |      |  + r4  |              |        |
  	 * |  	  +--------+              |        |
  	 * |  	  |        |              |        |
  	 * |  	  |        |              |        |
  	 * |  	  +--------+              +--------+
  	 */
  	if (!region16_union_rect(&region, &region, &r4))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r2_r3_r4, 3))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  
  static int test_from_weston(void)
  {
  	/*
  	 * 0: 0,0 -> 640,32 (w=640 h=32)
  	 * 1: 236,169 -> 268,201 (w=32 h=32)
  	 * 2: 246,258 -> 278,290 (w=32 h=32)
  	 */
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0,   0, 640,  32};
  	RECTANGLE_16 r2 = {236, 169, 268, 201};
  	RECTANGLE_16 r3 = {246, 258, 278, 290};
  	RECTANGLE_16 r1_r2_r3[] =
  	{
  		{  0,   0, 640,  32},
  		{236, 169, 268, 201},
  		{246, 258, 278, 290}
  	};
  	region16_init(&region);
  
  	/*
  	 * +===============================================================
  	 * |+-------------------------------------------------------------+
  	 * ||              r1                                             |
  	 * |+-------------------------------------------------------------+
  	 * |
  	 * |       +---------------+
  	 * |       |     r2        |
  	 * |       +---------------+
  	 * |
  	 * |         +---------------+
  	 * |         |     r3        |
  	 * |         +---------------+
  	 * |
  	 */
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r2))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r3))
  		goto out;
  
  	rects = region16_rects(&region, &nbRects);
  
  	if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r2_r3, 3))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  static int test_r1_inter_r3(void)
  {
  	REGION16 region, intersection;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r3 = {150, 151, 250, 251};
  	RECTANGLE_16 r1_inter_r3[] =
  	{
  		{150, 151, 200, 201},
  	};
  	region16_init(&region);
  	region16_init(&intersection);
  
  	/*
  	 * +===============================================================
  	 * |
  	 * |+-----+
  	 * || r1  |
  	 * ||   +-+------+             +-+
  	 * ||   |    r3  | r1&r3       | |
  	 * |+---+        | ====>       +-+
  	 * |    |        |
  	 * |    +--------+
  	 */
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_intersects_rect(&region, &r3))
  		goto out;
  
  	if (!region16_intersect_rect(&intersection, &region, &r3))
  		goto out;
  
  	rects = region16_rects(&intersection, &nbRects);
  
  	if (!rects || nbRects != 1 || !compareRectangles(rects, r1_inter_r3, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	region16_uninit(&intersection);
  	return retCode;
  }
  
  static int test_r1_r3_inter_r11(void)
  {
  	REGION16 region, intersection;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects;
  	RECTANGLE_16 r1 = {  0, 101, 200, 201};
  	RECTANGLE_16 r3 = {150, 151, 250, 251};
  	RECTANGLE_16 r11 = {170, 151, 600, 301};
  	RECTANGLE_16 r1_r3_inter_r11[] =
  	{
  		{170, 151, 250, 251},
  	};
  	region16_init(&region);
  	region16_init(&intersection);
  
  	/*
  	 * +===============================================================
  	 * |
  	 * |+-----+
  	 * ||     |
  	 * ||     +------+
  	 * || r1+r3      |          (r1+r3) & r11
  	 * ||     +----------------+             +--------+
  	 * |+---+ |      |         |   ====>     |        |
  	 * |    | |      |         |             |        |
  	 * |    | |      |         |             |        |
  	 * |    +-|------+         |             +--------+
  	 * |      |            r11 |
  	 * |      +----------------+
  	 *
  	 *
  	 * R1+R3 is made of 3 bands, R11 overlap the second and the third band. The
  	 * intersection is made of two band that must be reassembled to give only
  	 * one
  	 */
  	if (!region16_union_rect(&region, &region, &r1))
  		goto out;
  
  	if (!region16_union_rect(&region, &region, &r3))
  		goto out;
  
  	if (!region16_intersects_rect(&region, &r11))
  		goto out;
  
  	if (!region16_intersect_rect(&intersection, &region, &r11))
  		goto out;
  
  	rects = region16_rects(&intersection, &nbRects);
  
  	if (!rects || nbRects != 1 || !compareRectangles(rects, r1_r3_inter_r11, nbRects))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&intersection);
  	region16_uninit(&region);
  	return retCode;
  }
  
  static int test_norbert_case(void)
  {
  	REGION16 region, intersection;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects, i;
  	RECTANGLE_16 inRectangles[5] =
  	{
  		{1680,    0, 1920,  242},
  		{ 294,  242,  971,  776},
  		{1680,  242, 1920,  776},
  		{1680,  776, 1920, 1036},
  		{   2, 1040,   53, 1078}
  	};
  	RECTANGLE_16 screenRect =
  	{
  		0, 0, 1920, 1080
  	};
  	RECTANGLE_16 expected_inter_extents =
  	{
  		2, 0, 1920, 1078
  	};
  	region16_init(&region);
  	region16_init(&intersection);
  
  	/*
  	 * Consider following as a screen with resolution 1920*1080
  	 *      | |    |     |           |               |      |
  	 *      | |2   |53   |294        |971            |1680  |
  	 *      | |    |     |           |               |      |
  	 *    0 +=+======================================+======+
  	 *      | |                                      |      |
  	 *      |                                        |  R[0]|
  	 *  242 |            +-----------+               +------+
  	 *      | |          |           |               |      |
  	 *      |            |           |               |      |
  	 *      |            |       R[1]|               |  R[2]|
  	 *  776 | |          +-----------+               +------+
  	 *      |                                        |      |
  	 *      |                                        |  R[3]|
  	 * 1036 | |                                      +------+
  	 * 1040 | +----+
  	 *      | |R[4]|                         Union of R[0-4]|
  	 * 1078 | +----+    -    -    -    -    -    -    -    -+
  	 * 1080 |
  	 *
  	 *
  	 * The result is union of R[0] - R[4].
  	 * After intersected with the full screen rect, the
  	 * result should keep the same.
  	 */
  	for (i = 0; i < 5; i++)
  	{
  		if (!region16_union_rect(&region, &region, &inRectangles[i]))
  			goto out;
  	}
  
  	if (!compareRectangles(region16_extents(&region), &expected_inter_extents, 1))
  		goto out;
  
  	if (!region16_intersect_rect(&intersection, &region, &screenRect))
  		goto out;
  
  	rects = region16_rects(&intersection, &nbRects);
  
  	if (!rects || nbRects != 5 || !compareRectangles(rects, inRectangles, nbRects))
  		goto out;
  
  	if (!compareRectangles(region16_extents(&intersection), &expected_inter_extents, 1))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&intersection);
  	region16_uninit(&region);
  	return retCode;
  }
  
  static int test_norbert2_case(void)
  {
  	REGION16 region;
  	int retCode = -1;
  	const RECTANGLE_16* rects;
  	UINT32 nbRects = 0;
  	RECTANGLE_16 rect1 = {  464, 696,   476,  709 };
  	RECTANGLE_16 rect2 = {    0,   0,  1024,   32 };
  	region16_init(&region);
  
  	if (!region16_union_rect(&region, &region, &rect1))
  	{
  		fprintf(stderr, "%s: Error 1 - region16_union_rect failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	if (!(rects = region16_rects(&region, &nbRects)))
  	{
  		fprintf(stderr, "%s: Error 2 - region16_rects failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	if (nbRects != 1)
  	{
  		fprintf(stderr, "%s: Error 3 - expected nbRects == 1 but got %"PRIu32"\n", __FUNCTION__, nbRects);
  		goto out;
  	}
  
  	if (!compareRectangles(&rects[0], &rect1, 1))
  	{
  		fprintf(stderr, "%s: Error 4 - compare failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	if (!region16_union_rect(&region, &region, &rect2))
  	{
  		fprintf(stderr, "%s: Error 5 - region16_union_rect failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	if (!(rects = region16_rects(&region, &nbRects)))
  	{
  		fprintf(stderr, "%s: Error 6 - region16_rects failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	if (nbRects != 2)
  	{
  		fprintf(stderr, "%s: Error 7 - expected nbRects == 2 but got %"PRIu32"\n", __FUNCTION__, nbRects);
  		goto out;
  	}
  
  	if (!compareRectangles(&rects[0], &rect2, 1))
  	{
  		fprintf(stderr, "%s: Error 8 - compare failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	if (!compareRectangles(&rects[1], &rect1, 1))
  	{
  		fprintf(stderr, "%s: Error 9 - compare failed\n", __FUNCTION__);
  		goto out;
  	}
  
  	retCode = 0;
  out:
  	region16_uninit(&region);
  	return retCode;
  }
  
  static int test_empty_rectangle(void)
  {
  	REGION16 region, intersection;
  	int retCode = -1;
  	int i;
  	RECTANGLE_16 emptyRectangles[3] =
  	{
  		{   0,    0,    0,    0},
  		{  10,   10,   10,   11},
  		{  10,   10,   11,   10}
  	};
  	RECTANGLE_16 firstRect =
  	{
  		0, 0, 100, 100
  	};
  	RECTANGLE_16 anotherRect =
  	{
  		100, 100,  200,  200
  	};
  	RECTANGLE_16 expected_inter_extents =
  	{
  		0, 0, 0, 0
  	};
  	region16_init(&region);
  	region16_init(&intersection);
  
  	/* Check for empty rectangles */
  	for (i = 0; i < 3; i++)
  	{
  		if (!rectangle_is_empty(&emptyRectangles[i]))
  			goto out;
  	}
  
  	/* Check for non-empty rectangles */
  	if (rectangle_is_empty(&firstRect))
  		goto out;
  
  	/* Intersect 2 non-intersect rectangle, result should be empty */
  	if (!region16_union_rect(&region, &region, &firstRect))
  		goto out;
  
  	if (!region16_intersect_rect(&region, &region, &anotherRect))
  		goto out;
  
  	if (!compareRectangles(region16_extents(&region), &expected_inter_extents, 1))
  		goto out;
  
  	if (!region16_is_empty(&region))
  		goto out;
  
  	if (!rectangle_is_empty(region16_extents(&intersection)))
  		goto out;
  
  	retCode = 0;
  out:
  	region16_uninit(&intersection);
  	region16_uninit(&region);
  	return retCode;
  }
  
  typedef int (*TestFunction)(void);
  struct UnitaryTest
  {
  	const char* name;
  	TestFunction func;
  };
  
  static struct UnitaryTest tests[] =
  {
  	{"Basic trivial tests", 	test_basic},
  	{"R1+R3 and R3+R1", 		test_r1_r3},
  	{"R1+R5",					test_r1_r5},
  	{"R1+R6",					test_r1_r6},
  	{"R9+R10", 					test_r9_r10},
  	{"R1+R2+R4", 				test_r1_r2_r4},
  	{"R1+R7+R8 in many orders", test_r1_r7_r8},
  	{"R1+R2+R3+R4",     		test_r1_r2_r3_r4},
  	{"data from weston",        test_from_weston},
  	{"R1 & R3",					test_r1_inter_r3},
  	{"(R1+R3)&R11 (band merge)", test_r1_r3_inter_r11},
  	{"norbert's case",			test_norbert_case},
  	{"norbert's case 2", 		test_norbert2_case},
  	{"empty rectangle case",	test_empty_rectangle},
  
  	{NULL, NULL}
  };
  
  int TestFreeRDPRegion(int argc, char* argv[])
  {
  	int i, testNb = 0;
  	int retCode = -1;
  	WINPR_UNUSED(argc);
  	WINPR_UNUSED(argv);
  
  	for (i = 0; tests[i].func; i++)
  	{
  		testNb++;
  		fprintf(stderr, "%d: %s\n", testNb, tests[i].name);
  		retCode = tests[i].func();
  
  		if (retCode < 0)
  			break;
  	}
  
  	if (retCode < 0)
  		fprintf(stderr, "failed for test %d\n", testNb);
  
  	return retCode;
  }
  