1
0
Fork 0
mutter-performance-source/src/tests/boxes-tests.c
Jonas Ådahl 2f4a68c8c3 Clean up include macros mess
The order and way include macros were structured was chaotic, with no
real common thread between files. Try to tidy up the mess with some
common scheme, to make things look less messy.
2018-11-06 17:17:36 +01:00

1395 lines
49 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter box operation testing program */
/*
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "tests/boxes-tests.h"
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xutil.h>
#include <time.h>
#include <math.h>
#include "core/boxes-private.h"
#define NUM_RANDOM_RUNS 10000
static void
init_random_ness (void)
{
srand (time (NULL));
}
static void
get_random_rect (MetaRectangle *rect)
{
rect->x = rand () % 1600;
rect->y = rand () % 1200;
rect->width = rand () % 1600 + 1;
rect->height = rand () % 1200 + 1;
}
static MetaRectangle*
new_meta_rect (int x, int y, int width, int height)
{
MetaRectangle* temporary;
temporary = g_new (MetaRectangle, 1);
temporary->x = x;
temporary->y = y;
temporary->width = width;
temporary->height = height;
return temporary;
}
static MetaStrut*
new_meta_strut (int x, int y, int width, int height, int side)
{
MetaStrut* temporary;
temporary = g_new (MetaStrut, 1);
temporary->rect = meta_rect(x, y, width, height);
temporary->side = side;
return temporary;
}
static MetaEdge*
new_screen_edge (int x, int y, int width, int height, int side_type)
{
MetaEdge* temporary;
temporary = g_new (MetaEdge, 1);
temporary->rect.x = x;
temporary->rect.y = y;
temporary->rect.width = width;
temporary->rect.height = height;
temporary->side_type = side_type;
temporary->edge_type = META_EDGE_SCREEN;
return temporary;
}
static MetaEdge*
new_monitor_edge (int x, int y, int width, int height, int side_type)
{
MetaEdge* temporary;
temporary = g_new (MetaEdge, 1);
temporary->rect.x = x;
temporary->rect.y = y;
temporary->rect.width = width;
temporary->rect.height = height;
temporary->side_type = side_type;
temporary->edge_type = META_EDGE_MONITOR;
return temporary;
}
static void
test_area (void)
{
MetaRectangle temp;
int i;
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
get_random_rect (&temp);
g_assert (meta_rectangle_area (&temp) == temp.width * temp.height);
}
temp = meta_rect (0, 0, 5, 7);
g_assert (meta_rectangle_area (&temp) == 35);
}
static void
test_intersect (void)
{
MetaRectangle a = {100, 200, 50, 40};
MetaRectangle b = { 0, 50, 110, 152};
MetaRectangle c = { 0, 0, 10, 10};
MetaRectangle d = {100, 100, 50, 50};
MetaRectangle b_intersect_d = {100, 100, 10, 50};
MetaRectangle temp;
MetaRectangle temp2;
meta_rectangle_intersect (&a, &b, &temp);
temp2 = meta_rect (100, 200, 10, 2);
g_assert (meta_rectangle_equal (&temp, &temp2));
g_assert (meta_rectangle_area (&temp) == 20);
meta_rectangle_intersect (&a, &c, &temp);
g_assert (meta_rectangle_area (&temp) == 0);
meta_rectangle_intersect (&a, &d, &temp);
g_assert (meta_rectangle_area (&temp) == 0);
meta_rectangle_intersect (&b, &d, &b);
g_assert (meta_rectangle_equal (&b, &b_intersect_d));
}
static void
test_equal (void)
{
MetaRectangle a = {10, 12, 4, 18};
MetaRectangle b = a;
MetaRectangle c = {10, 12, 4, 19};
MetaRectangle d = {10, 12, 7, 18};
MetaRectangle e = {10, 62, 4, 18};
MetaRectangle f = {27, 12, 4, 18};
g_assert ( meta_rectangle_equal (&a, &b));
g_assert (!meta_rectangle_equal (&a, &c));
g_assert (!meta_rectangle_equal (&a, &d));
g_assert (!meta_rectangle_equal (&a, &e));
g_assert (!meta_rectangle_equal (&a, &f));
}
static void
test_overlap_funcs (void)
{
MetaRectangle temp1, temp2;
int i;
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
get_random_rect (&temp1);
get_random_rect (&temp2);
g_assert (meta_rectangle_overlap (&temp1, &temp2) ==
(meta_rectangle_horiz_overlap (&temp1, &temp2) &&
meta_rectangle_vert_overlap (&temp1, &temp2)));
}
temp1 = meta_rect ( 0, 0, 10, 10);
temp2 = meta_rect (20, 0, 10, 5);
g_assert (!meta_rectangle_overlap (&temp1, &temp2));
g_assert (!meta_rectangle_horiz_overlap (&temp1, &temp2));
g_assert ( meta_rectangle_vert_overlap (&temp1, &temp2));
}
static void
test_basic_fitting (void)
{
MetaRectangle temp1, temp2, temp3;
int i;
/* Four cases:
* case temp1 fits temp2 temp1 could fit temp2
* 1 Y Y
* 2 N Y
* 3 Y N
* 4 N N
* Of the four cases, case 3 is impossible. An alternate way of looking
* at this table is that either the middle column must be no, or the last
* column must be yes. So we test that. Also, we can repeat the test
* reversing temp1 and temp2.
*/
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
get_random_rect (&temp1);
get_random_rect (&temp2);
g_assert (meta_rectangle_contains_rect (&temp1, &temp2) == FALSE ||
meta_rectangle_could_fit_rect (&temp1, &temp2) == TRUE);
g_assert (meta_rectangle_contains_rect (&temp2, &temp1) == FALSE ||
meta_rectangle_could_fit_rect (&temp2, &temp1) == TRUE);
}
temp1 = meta_rect ( 0, 0, 10, 10);
temp2 = meta_rect ( 5, 5, 5, 5);
temp3 = meta_rect ( 8, 2, 3, 7);
g_assert ( meta_rectangle_contains_rect (&temp1, &temp2));
g_assert (!meta_rectangle_contains_rect (&temp2, &temp1));
g_assert (!meta_rectangle_contains_rect (&temp1, &temp3));
g_assert ( meta_rectangle_could_fit_rect (&temp1, &temp3));
g_assert (!meta_rectangle_could_fit_rect (&temp3, &temp2));
}
static void
free_strut_list (GSList *struts)
{
GSList *tmp = struts;
while (tmp)
{
g_free (tmp->data);
tmp = tmp->next;
}
g_slist_free (struts);
}
static GSList*
get_strut_list (int which)
{
GSList *ans;
MetaSide wc = 0; /* wc == who cares? ;-) */
ans = NULL;
g_assert (which >=0 && which <= 6);
switch (which)
{
case 0:
break;
case 1:
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP));
ans = g_slist_prepend (ans, new_meta_strut ( 400, 1160, 1600, 40, META_SIDE_BOTTOM));
break;
case 2:
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100, 400, 100, META_SIDE_BOTTOM));
ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150, 150, 50, META_SIDE_BOTTOM));
break;
case 3:
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100, 400, 100, META_SIDE_LEFT));
ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150, 80, 50, META_SIDE_BOTTOM));
ans = g_slist_prepend (ans, new_meta_strut ( 700, 525, 200, 150, wc));
break;
case 4:
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 800, 1200, META_SIDE_LEFT));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 0, 1600, 20, META_SIDE_TOP));
break;
case 5:
ans = g_slist_prepend (ans, new_meta_strut ( 800, 0, 1600, 20, META_SIDE_TOP));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 800, 1200, META_SIDE_LEFT));
ans = g_slist_prepend (ans, new_meta_strut ( 800, 10, 800, 1200, META_SIDE_RIGHT));
break;
case 6:
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 40, META_SIDE_TOP));
ans = g_slist_prepend (ans, new_meta_strut ( 0, 0, 1600, 20, META_SIDE_TOP));
break;
}
return ans;
}
static GList*
get_screen_region (int which)
{
GList *ret;
GSList *struts;
MetaRectangle basic_rect;
basic_rect = meta_rect (0, 0, 1600, 1200);
ret = NULL;
struts = get_strut_list (which);
ret = meta_rectangle_get_minimal_spanning_set_for_region (&basic_rect, struts);
free_strut_list (struts);
return ret;
}
static GList*
get_screen_edges (int which)
{
GList *ret;
GSList *struts;
MetaRectangle basic_rect;
basic_rect = meta_rect (0, 0, 1600, 1200);
ret = NULL;
struts = get_strut_list (which);
ret = meta_rectangle_find_onscreen_edges (&basic_rect, struts);
free_strut_list (struts);
return ret;
}
static GList*
get_monitor_edges (int which_monitor_set, int which_strut_set)
{
GList *ret;
GSList *struts;
GList *xins;
xins = NULL;
g_assert (which_monitor_set >=0 && which_monitor_set <= 3);
switch (which_monitor_set)
{
case 0:
xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 1200));
break;
case 1:
xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 800, 1200));
xins = g_list_prepend (xins, new_meta_rect (800, 0, 800, 1200));
break;
case 2:
xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 600));
xins = g_list_prepend (xins, new_meta_rect ( 0, 600, 1600, 600));
break;
case 3:
xins = g_list_prepend (xins, new_meta_rect ( 0, 0, 1600, 600));
xins = g_list_prepend (xins, new_meta_rect ( 0, 600, 800, 600));
xins = g_list_prepend (xins, new_meta_rect (800, 600, 800, 600));
break;
}
ret = NULL;
struts = get_strut_list (which_strut_set);
ret = meta_rectangle_find_nonintersected_monitor_edges (xins, struts);
free_strut_list (struts);
meta_rectangle_free_list_and_elements (xins);
return ret;
}
#if 0
static void
test_merge_regions (void)
{
/* logarithmically distributed random number of struts (range?)
* logarithmically distributed random size of struts (up to screen size???)
* uniformly distributed location of center of struts (within screen)
* merge all regions that are possible
* print stats on problem setup
* number of (non-completely-occluded?) struts
* percentage of screen covered
* length of resulting non-minimal spanning set
* length of resulting minimal spanning set
* print stats on merged regions:
* number boxes merged
* number of those merges that were of the form A contains B
* number of those merges that were of the form A partially contains B
* number of those merges that were of the form A is adjacent to B
*/
GList* region;
GList* compare;
int num_contains, num_merged, num_part_contains, num_adjacent;
num_contains = num_merged = num_part_contains = num_adjacent = 0;
compare = region = get_screen_region (2);
g_assert (region);
printf ("Merging stats:\n");
printf (" Length of initial list: %d\n", g_list_length (region));
#ifdef PRINT_DEBUG
char rect1[RECT_LENGTH], rect2[RECT_LENGTH];
char region_list[(RECT_LENGTH + 2) * g_list_length (region)];
meta_rectangle_region_to_string (region, ", ", region_list);
printf (" Initial rectangles: %s\n", region_list);
#endif
while (compare && compare->next)
{
MetaRectangle *a = compare->data;
GList *other = compare->next;
g_assert (a->width > 0 && a->height > 0);
while (other)
{
MetaRectangle *b = other->data;
GList *delete_me = NULL;
g_assert (b->width > 0 && b->height > 0);
#ifdef PRINT_DEBUG
printf (" -- Comparing %s to %s --\n",
meta_rectangle_to_string (a, rect1),
meta_rectangle_to_string (b, rect2));
#endif
/* If a contains b, just remove b */
if (meta_rectangle_contains_rect (a, b))
{
delete_me = other;
num_contains++;
num_merged++;
}
/* If b contains a, just remove a */
else if (meta_rectangle_contains_rect (a, b))
{
delete_me = compare;
num_contains++;
num_merged++;
}
/* If a and b might be mergeable horizontally */
else if (a->y == b->y && a->height == b->height)
{
/* If a and b overlap */
if (meta_rectangle_overlap (a, b))
{
int new_x = MIN (a->x, b->x);
a->width = MAX (a->x + a->width, b->x + b->width) - new_x;
a->x = new_x;
delete_me = other;
num_part_contains++;
num_merged++;
}
/* If a and b are adjacent */
else if (a->x + a->width == b->x || a->x == b->x + b->width)
{
int new_x = MIN (a->x, b->x);
a->width = MAX (a->x + a->width, b->x + b->width) - new_x;
a->x = new_x;
delete_me = other;
num_adjacent++;
num_merged++;
}
}
/* If a and b might be mergeable vertically */
else if (a->x == b->x && a->width == b->width)
{
/* If a and b overlap */
if (meta_rectangle_overlap (a, b))
{
int new_y = MIN (a->y, b->y);
a->height = MAX (a->y + a->height, b->y + b->height) - new_y;
a->y = new_y;
delete_me = other;
num_part_contains++;
num_merged++;
}
/* If a and b are adjacent */
else if (a->y + a->height == b->y || a->y == b->y + b->height)
{
int new_y = MIN (a->y, b->y);
a->height = MAX (a->y + a->height, b->y + b->height) - new_y;
a->y = new_y;
delete_me = other;
num_adjacent++;
num_merged++;
}
}
other = other->next;
/* Delete any rectangle in the list that is no longer wanted */
if (delete_me != NULL)
{
#ifdef PRINT_DEBUG
MetaRectangle *bla = delete_me->data;
printf (" Deleting rect %s\n",
meta_rectangle_to_string (bla, rect1));
#endif
/* Deleting the rect we're compare others to is a little tricker */
if (compare == delete_me)
{
compare = compare->next;
other = compare->next;
a = compare->data;
}
/* Okay, we can free it now */
g_free (delete_me->data);
region = g_list_delete_link (region, delete_me);
}
#ifdef PRINT_DEBUG
char region_list[(RECT_LENGTH + 2) * g_list_length (region)];
meta_rectangle_region_to_string (region, ", ", region_list);
printf (" After comparison, new list is: %s\n", region_list);
#endif
}
compare = compare->next;
}
printf (" Num rectangles contained in others : %d\n",
num_contains);
printf (" Num rectangles partially contained in others: %d\n",
num_part_contains);
printf (" Num rectangles adjacent to others : %d\n",
num_adjacent);
printf (" Num rectangles merged with others : %d\n",
num_merged);
#ifdef PRINT_DEBUG
char region_list2[(RECT_LENGTH + 2) * g_list_length (region)];
meta_rectangle_region_to_string (region, ", ", region_list2);
printf (" Final rectangles: %s\n", region_list2);
#endif
meta_rectangle_free_spanning_set (region);
region = NULL;
printf ("%s passed.\n", G_STRFUNC);
}
#endif
static void
verify_lists_are_equal (GList *code, GList *answer)
{
int which = 0;
while (code && answer)
{
MetaRectangle *a = code->data;
MetaRectangle *b = answer->data;
if (a->x != b->x ||
a->y != b->y ||
a->width != b->width ||
a->height != b->height)
{
g_error ("%dth item in code answer answer lists do not match; "
"code rect: %d,%d + %d,%d; answer rect: %d,%d + %d,%d\n",
which,
a->x, a->y, a->width, a->height,
b->x, b->y, b->width, b->height);
}
code = code->next;
answer = answer->next;
which++;
}
/* Ought to be at the end of both lists; check if we aren't */
if (code)
{
MetaRectangle *tmp = code->data;
g_error ("code list longer than answer list by %d items; "
"first extra item: %d,%d +%d,%d\n",
g_list_length (code),
tmp->x, tmp->y, tmp->width, tmp->height);
}
if (answer)
{
MetaRectangle *tmp = answer->data;
g_error ("answer list longer than code list by %d items; "
"first extra item: %d,%d +%d,%d\n",
g_list_length (answer),
tmp->x, tmp->y, tmp->width, tmp->height);
}
}
static void
test_regions_okay (void)
{
GList* region;
GList* tmp;
/*************************************************************/
/* Make sure test region 0 has the right spanning rectangles */
/*************************************************************/
region = get_screen_region (0);
tmp = NULL;
tmp = g_list_prepend (tmp, new_meta_rect (0, 0, 1600, 1200));
verify_lists_are_equal (region, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (region);
/*************************************************************/
/* Make sure test region 1 has the right spanning rectangles */
/*************************************************************/
region = get_screen_region (1);
tmp = NULL;
tmp = g_list_prepend (tmp, new_meta_rect (0, 20, 400, 1180));
tmp = g_list_prepend (tmp, new_meta_rect (0, 20, 1600, 1140));
verify_lists_are_equal (region, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (region);
/*************************************************************/
/* Make sure test region 2 has the right spanning rectangles */
/*************************************************************/
region = get_screen_region (2);
tmp = NULL;
tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 300, 1180));
tmp = g_list_prepend (tmp, new_meta_rect ( 450, 20, 350, 1180));
tmp = g_list_prepend (tmp, new_meta_rect (1200, 20, 400, 1180));
tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 800, 1130));
tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 1600, 1080));
verify_lists_are_equal (region, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (region);
/*************************************************************/
/* Make sure test region 3 has the right spanning rectangles */
/*************************************************************/
region = get_screen_region (3);
tmp = NULL;
tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 300, 1180)); /* 354000 */
tmp = g_list_prepend (tmp, new_meta_rect ( 380, 20, 1220, 1180)); /* 377600 */
tmp = g_list_prepend (tmp, new_meta_rect ( 0, 20, 1600, 1130)); /* 791000 */
#if 0
printf ("Got to here...\n");
char region_list[(RECT_LENGTH+2) * g_list_length (region)];
char tmp_list[ (RECT_LENGTH+2) * g_list_length (tmp)];
meta_rectangle_region_to_string (region, ", ", region_list);
meta_rectangle_region_to_string (region, ", ", tmp_list);
printf ("%s vs. %s\n", region_list, tmp_list);
#endif
verify_lists_are_equal (region, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (region);
/*************************************************************/
/* Make sure test region 4 has the right spanning rectangles */
/*************************************************************/
region = get_screen_region (4);
tmp = NULL;
tmp = g_list_prepend (tmp, new_meta_rect ( 800, 20, 800, 1180));
verify_lists_are_equal (region, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (region);
/*************************************************************/
/* Make sure test region 5 has the right spanning rectangles */
/*************************************************************/
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"Region to merge was empty!*");
region = get_screen_region (5);
g_test_assert_expected_messages ();
verify_lists_are_equal (region, NULL);
/* FIXME: Still to do:
* - Create random struts and check the regions somehow
*/
}
static void
test_region_fitting (void)
{
GList* region;
MetaRectangle rect;
/* See test_basic_fitting() for how/why these automated random tests work */
int i;
region = get_screen_region (3);
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
get_random_rect (&rect);
g_assert (meta_rectangle_contained_in_region (region, &rect) == FALSE ||
meta_rectangle_could_fit_in_region (region, &rect) == TRUE);
}
meta_rectangle_free_list_and_elements (region);
/* Do some manual tests too */
region = get_screen_region (1);
rect = meta_rect (50, 50, 400, 400);
g_assert (meta_rectangle_could_fit_in_region (region, &rect));
g_assert (meta_rectangle_contained_in_region (region, &rect));
rect = meta_rect (250, 0, 500, 1150);
g_assert (!meta_rectangle_could_fit_in_region (region, &rect));
g_assert (!meta_rectangle_contained_in_region (region, &rect));
rect = meta_rect (250, 0, 400, 400);
g_assert (meta_rectangle_could_fit_in_region (region, &rect));
g_assert (!meta_rectangle_contained_in_region (region, &rect));
meta_rectangle_free_list_and_elements (region);
region = get_screen_region (2);
rect = meta_rect (1000, 50, 600, 1100);
g_assert (meta_rectangle_could_fit_in_region (region, &rect));
g_assert (!meta_rectangle_contained_in_region (region, &rect));
meta_rectangle_free_list_and_elements (region);
}
static void
test_clamping_to_region (void)
{
GList* region;
MetaRectangle rect;
MetaRectangle min_size;
FixedDirections fixed_directions;
int i;
min_size.height = min_size.width = 1;
fixed_directions = 0;
region = get_screen_region (3);
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
MetaRectangle temp;
get_random_rect (&rect);
temp = rect;
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_assert (meta_rectangle_could_fit_in_region (region, &rect) == TRUE);
g_assert (rect.x == temp.x && rect.y == temp.y);
}
meta_rectangle_free_list_and_elements (region);
/* Do some manual tests too */
region = get_screen_region (1);
rect = meta_rect (50, 50, 10000, 10000);
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_assert (rect.width == 1600 && rect.height == 1140);
rect = meta_rect (275, -50, 410, 10000);
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_assert (rect.width == 400 && rect.height == 1180);
rect = meta_rect (50, 50, 10000, 10000);
min_size.height = 1170;
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_assert (rect.width == 400 && rect.height == 1180);
rect = meta_rect (50, 50, 10000, 10000);
min_size.width = 600; min_size.height = 1170;
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"No rect whose size to clamp to found*");
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_test_assert_expected_messages ();
g_assert (rect.width == 600 && rect.height == 1170);
rect = meta_rect (350, 50, 100, 1100);
min_size.width = 1; min_size.height = 1;
fixed_directions = FIXED_DIRECTION_X;
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_assert (rect.width == 100 && rect.height == 1100);
rect = meta_rect (300, 70, 500, 1100);
min_size.width = 1; min_size.height = 1;
fixed_directions = FIXED_DIRECTION_Y;
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_assert (rect.width == 400 && rect.height == 1100);
rect = meta_rect (300, 70, 999999, 999999);
min_size.width = 100; min_size.height = 200;
fixed_directions = FIXED_DIRECTION_Y;
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"No rect whose size to clamp to found*");
meta_rectangle_clamp_to_fit_into_region (region,
fixed_directions,
&rect,
&min_size);
g_test_assert_expected_messages ();
g_assert (rect.width == 100 && rect.height == 999999);
meta_rectangle_free_list_and_elements (region);
}
static gboolean
rect_overlaps_region (const GList *spanning_rects,
const MetaRectangle *rect)
{
/* FIXME: Should I move this to boxes.[ch]? */
const GList *temp;
gboolean overlaps;
temp = spanning_rects;
overlaps = FALSE;
while (!overlaps && temp != NULL)
{
overlaps = overlaps || meta_rectangle_overlap (temp->data, rect);
temp = temp->next;
}
return overlaps;
}
gboolean time_to_print = FALSE;
static void
test_clipping_to_region (void)
{
GList* region;
MetaRectangle rect, temp;
FixedDirections fixed_directions = 0;
int i;
region = get_screen_region (3);
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
get_random_rect (&rect);
if (rect_overlaps_region (region, &rect))
{
meta_rectangle_clip_to_region (region, 0, &rect);
g_assert (meta_rectangle_contained_in_region (region, &rect) == TRUE);
}
}
meta_rectangle_free_list_and_elements (region);
/* Do some manual tests too */
region = get_screen_region (2);
rect = meta_rect (-50, -10, 10000, 10000);
meta_rectangle_clip_to_region (region,
fixed_directions,
&rect);
g_assert (meta_rectangle_equal (region->data, &rect));
rect = meta_rect (300, 1000, 400, 200);
temp = meta_rect (300, 1000, 400, 150);
meta_rectangle_clip_to_region (region,
fixed_directions,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (400, 1000, 300, 200);
temp = meta_rect (450, 1000, 250, 200);
meta_rectangle_clip_to_region (region,
fixed_directions,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (400, 1000, 300, 200);
temp = meta_rect (400, 1000, 300, 150);
meta_rectangle_clip_to_region (region,
FIXED_DIRECTION_X,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (400, 1000, 300, 200);
temp = meta_rect (400, 1000, 300, 150);
meta_rectangle_clip_to_region (region,
FIXED_DIRECTION_X,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
meta_rectangle_free_list_and_elements (region);
}
static void
test_shoving_into_region (void)
{
GList* region;
MetaRectangle rect, temp;
FixedDirections fixed_directions = 0;
int i;
region = get_screen_region (3);
for (i = 0; i < NUM_RANDOM_RUNS; i++)
{
get_random_rect (&rect);
if (meta_rectangle_could_fit_in_region (region, &rect))
{
meta_rectangle_shove_into_region (region, 0, &rect);
g_assert (meta_rectangle_contained_in_region (region, &rect));
}
}
meta_rectangle_free_list_and_elements (region);
/* Do some manual tests too */
region = get_screen_region (2);
rect = meta_rect (300, 1000, 400, 200);
temp = meta_rect (300, 950, 400, 200);
meta_rectangle_shove_into_region (region,
fixed_directions,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (425, 1000, 300, 200);
temp = meta_rect (450, 1000, 300, 200);
meta_rectangle_shove_into_region (region,
fixed_directions,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (425, 1000, 300, 200);
temp = meta_rect (425, 950, 300, 200);
meta_rectangle_shove_into_region (region,
FIXED_DIRECTION_X,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 300, 1000, 400, 200);
temp = meta_rect (1200, 1000, 400, 200);
meta_rectangle_shove_into_region (region,
FIXED_DIRECTION_Y,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 800, 1150, 400, 50); /* Completely "offscreen" :) */
temp = meta_rect ( 800, 1050, 400, 50);
meta_rectangle_shove_into_region (region,
0,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (-1000, 0, 400, 150); /* Offscreen in 2 directions */
temp = meta_rect ( 0, 20, 400, 150);
meta_rectangle_shove_into_region (region,
0,
&rect);
g_assert (meta_rectangle_equal (&rect, &temp));
meta_rectangle_free_list_and_elements (region);
}
static void
verify_edge_lists_are_equal (GList *code, GList *answer)
{
int which = 0;
while (code && answer)
{
MetaEdge *a = code->data;
MetaEdge *b = answer->data;
if (!meta_rectangle_equal (&a->rect, &b->rect) ||
a->side_type != b->side_type ||
a->edge_type != b->edge_type)
{
g_error ("%dth item in code answer answer lists do not match; "
"code rect: %d,%d + %d,%d; answer rect: %d,%d + %d,%d\n",
which,
a->rect.x, a->rect.y, a->rect.width, a->rect.height,
b->rect.x, b->rect.y, b->rect.width, b->rect.height);
}
code = code->next;
answer = answer->next;
which++;
}
/* Ought to be at the end of both lists; check if we aren't */
if (code)
{
MetaEdge *tmp = code->data;
g_error ("code list longer than answer list by %d items; "
"first extra item rect: %d,%d +%d,%d\n",
g_list_length (code),
tmp->rect.x, tmp->rect.y, tmp->rect.width, tmp->rect.height);
}
if (answer)
{
MetaEdge *tmp = answer->data;
g_error ("answer list longer than code list by %d items; "
"first extra item rect: %d,%d +%d,%d\n",
g_list_length (answer),
tmp->rect.x, tmp->rect.y, tmp->rect.width, tmp->rect.height);
}
}
static void
test_find_onscreen_edges (void)
{
GList* edges;
GList* tmp;
int left = META_DIRECTION_LEFT;
int right = META_DIRECTION_RIGHT;
int top = META_DIRECTION_TOP;
int bottom = META_DIRECTION_BOTTOM;
/*************************************************/
/* Make sure test region 0 has the correct edges */
/*************************************************/
edges = get_screen_edges (0);
tmp = NULL;
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 1600, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 0, 1600, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge (1600, 0, 0, 1200, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 0, 0, 1200, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************/
/* Make sure test region 1 has the correct edges */
/*************************************************/
edges = get_screen_edges (1);
tmp = NULL;
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 400, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 400, 1160, 1200, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 1600, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1140, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 400, 1160, 0, 40, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 0, 1180, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************/
/* Make sure test region 2 has the correct edges */
/*************************************************/
edges = get_screen_edges (2);
tmp = NULL;
tmp = g_list_prepend (tmp, new_screen_edge (1200, 1200, 400, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 450, 1200, 350, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 300, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 150, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 400, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 1600, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1180, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 0, 100, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 0, 50, right));
tmp = g_list_prepend (tmp, new_screen_edge (1200, 1100, 0, 100, left));
tmp = g_list_prepend (tmp, new_screen_edge ( 450, 1150, 0, 50, left));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 0, 1180, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************/
/* Make sure test region 3 has the correct edges */
/*************************************************/
edges = get_screen_edges (3);
tmp = NULL;
tmp = g_list_prepend (tmp, new_screen_edge (1200, 1200, 400, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 380, 1200, 420, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 300, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 80, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 400, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 700, 525, 200, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 700, 675, 200, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 1600, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1180, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1100, 0, 100, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 700, 525, 0, 150, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 300, 1150, 0, 50, right));
tmp = g_list_prepend (tmp, new_screen_edge (1200, 1100, 0, 100, left));
tmp = g_list_prepend (tmp, new_screen_edge ( 900, 525, 0, 150, left));
tmp = g_list_prepend (tmp, new_screen_edge ( 380, 1150, 0, 50, left));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 20, 0, 1180, left));
#if 0
#define FUDGE 50 /* number of edges */
char big_buffer1[(EDGE_LENGTH+2)*FUDGE], big_buffer2[(EDGE_LENGTH+2)*FUDGE];
meta_rectangle_edge_list_to_string (edges, "\n ", big_buffer1);
meta_rectangle_edge_list_to_string (tmp, "\n ", big_buffer2);
printf("Generated edge list:\n %s\nComparison edges list:\n %s\n",
big_buffer1, big_buffer2);
#endif
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************/
/* Make sure test region 4 has the correct edges */
/*************************************************/
edges = get_screen_edges (4);
tmp = NULL;
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 1200, 800, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 20, 800, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge (1600, 20, 0, 1180, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 800, 20, 0, 1180, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************/
/* Make sure test region 5 has the correct edges */
/*************************************************/
edges = get_screen_edges (5);
tmp = NULL;
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************/
/* Make sure test region 6 has the correct edges */
/*************************************************/
edges = get_screen_edges (6);
tmp = NULL;
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 1200, 1600, 0, bottom));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 40, 1600, 0, top));
tmp = g_list_prepend (tmp, new_screen_edge (1600, 40, 0, 1160, right));
tmp = g_list_prepend (tmp, new_screen_edge ( 0, 40, 0, 1160, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
}
static void
test_find_nonintersected_monitor_edges (void)
{
GList* edges;
GList* tmp;
int left = META_DIRECTION_LEFT;
int right = META_DIRECTION_RIGHT;
int top = META_DIRECTION_TOP;
int bottom = META_DIRECTION_BOTTOM;
/*************************************************************************/
/* Make sure test monitor set 0 for with region 0 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (0, 0);
tmp = NULL;
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 2 for with region 1 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (2, 1);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 1600, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 1600, 0, top));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 1 for with region 2 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (1, 2);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 20, 0, 1080, right));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 20, 0, 1180, left));
#if 0
#define FUDGE 50
char big_buffer1[(EDGE_LENGTH+2)*FUDGE], big_buffer2[(EDGE_LENGTH+2)*FUDGE];
meta_rectangle_edge_list_to_string (edges, "\n ", big_buffer1);
meta_rectangle_edge_list_to_string (tmp, "\n ", big_buffer2);
printf("Generated edge list:\n %s\nComparison edges list:\n %s\n",
big_buffer1, big_buffer2);
#endif
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 3 for with region 3 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (3, 3);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 900, 600, 700, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 700, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 900, 600, 700, 0, top));
tmp = g_list_prepend (tmp, new_monitor_edge ( 0, 600, 700, 0, top));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 675, 0, 425, right));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 675, 0, 525, left));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 3 for with region 4 has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (3, 4);
tmp = NULL;
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 800, 0, bottom));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 800, 0, top));
tmp = g_list_prepend (tmp, new_monitor_edge ( 800, 600, 0, 600, right));
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
/*************************************************************************/
/* Make sure test monitor set 3 for with region 5has the correct edges */
/*************************************************************************/
edges = get_monitor_edges (3, 5);
tmp = NULL;
verify_edge_lists_are_equal (edges, tmp);
meta_rectangle_free_list_and_elements (tmp);
meta_rectangle_free_list_and_elements (edges);
}
static void
test_gravity_resize (void)
{
MetaRectangle oldrect, rect, temp;
rect.x = -500; /* Some random amount not equal to oldrect.x to ensure that
* the resize is done with respect to oldrect instead of rect
*/
oldrect = meta_rect ( 50, 300, 250, 400);
temp = meta_rect ( 50, 300, 20, 5);
meta_rectangle_resize_with_gravity (&oldrect,
&rect,
NorthWestGravity,
20,
5);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 50, 300, 250, 400);
temp = meta_rect (165, 300, 20, 5);
meta_rectangle_resize_with_gravity (&rect,
&rect,
NorthGravity,
20,
5);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 50, 300, 250, 400);
temp = meta_rect (280, 300, 20, 5);
meta_rectangle_resize_with_gravity (&rect,
&rect,
NorthEastGravity,
20,
5);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 50, 300, 250, 400);
temp = meta_rect ( 50, 695, 50, 5);
meta_rectangle_resize_with_gravity (&rect,
&rect,
SouthWestGravity,
50,
5);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 50, 300, 250, 400);
temp = meta_rect (150, 695, 50, 5);
meta_rectangle_resize_with_gravity (&rect,
&rect,
SouthGravity,
50,
5);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 50, 300, 250, 400);
temp = meta_rect (250, 695, 50, 5);
meta_rectangle_resize_with_gravity (&rect,
&rect,
SouthEastGravity,
50,
5);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (167, 738, 237, 843);
temp = meta_rect (167, 1113, 832, 93);
meta_rectangle_resize_with_gravity (&rect,
&rect,
WestGravity,
832,
93);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect ( 167, 738, 237, 843);
temp = meta_rect (-131, 1113, 833, 93);
meta_rectangle_resize_with_gravity (&rect,
&rect,
CenterGravity,
832,
93);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (300, 1000, 400, 200);
temp = meta_rect (270, 994, 430, 212);
meta_rectangle_resize_with_gravity (&rect,
&rect,
EastGravity,
430,
211);
g_assert (meta_rectangle_equal (&rect, &temp));
rect = meta_rect (300, 1000, 400, 200);
temp = meta_rect (300, 1000, 430, 211);
meta_rectangle_resize_with_gravity (&rect,
&rect,
StaticGravity,
430,
211);
g_assert (meta_rectangle_equal (&rect, &temp));
}
#define EPSILON 0.000000001
static void
test_find_closest_point_to_line (void)
{
double x1, y1, x2, y2, px, py, rx, ry;
double answer_x, answer_y;
x1 = 3.0; y1 = 49.0;
x2 = 2.0; y2 = - 1.0;
px = -2.6; py = 19.1;
answer_x = 2.4; answer_y = 19;
meta_rectangle_find_linepoint_closest_to_point (x1, y1,
x2, y2,
px, py,
&rx, &ry);
g_assert (fabs (rx - answer_x) < EPSILON && fabs (ry - answer_y) < EPSILON);
/* Special test for x1 == x2, so that slop of line is infinite */
x1 = 3.0; y1 = 49.0;
x2 = 3.0; y2 = - 1.0;
px = -2.6; py = 19.1;
answer_x = 3.0; answer_y = 19.1;
meta_rectangle_find_linepoint_closest_to_point (x1, y1,
x2, y2,
px, py,
&rx, &ry);
g_assert (fabs (rx - answer_x) < EPSILON && fabs (ry - answer_y) < EPSILON);
/* Special test for y1 == y2, so perp line has slope of infinity */
x1 = 3.14; y1 = 7.0;
x2 = 2.718; y2 = 7.0;
px = -2.6; py = 19.1;
answer_x = -2.6; answer_y = 7;
meta_rectangle_find_linepoint_closest_to_point (x1, y1,
x2, y2,
px, py,
&rx, &ry);
g_assert (fabs (rx - answer_x) < EPSILON && fabs (ry - answer_y) < EPSILON);
/* Test when we the point we want to be closest to is actually on the line */
x1 = 3.0; y1 = 49.0;
x2 = 2.0; y2 = - 1.0;
px = 2.4; py = 19.0;
answer_x = 2.4; answer_y = 19;
meta_rectangle_find_linepoint_closest_to_point (x1, y1,
x2, y2,
px, py,
&rx, &ry);
g_assert (fabs (rx - answer_x) < EPSILON && fabs (ry - answer_y) < EPSILON);
}
void
init_boxes_tests (void)
{
init_random_ness ();
g_test_add_func ("/util/boxes/area", test_area);
g_test_add_func ("/util/boxes/intersect", test_intersect);
g_test_add_func ("/util/boxes/equal", test_equal);
g_test_add_func ("/util/boxes/overlap", test_overlap_funcs);
g_test_add_func ("/util/boxes/basic-fitting", test_basic_fitting);
g_test_add_func ("/util/boxes/regions-ok", test_regions_okay);
g_test_add_func ("/util/boxes/regions-fitting", test_region_fitting);
g_test_add_func ("/util/boxes/clamp-to-region", test_clamping_to_region);
g_test_add_func ("/util/boxes/clip-to-region", test_clipping_to_region);
g_test_add_func ("/util/boxes/shove-into-region", test_shoving_into_region);
/* And now the functions dealing with edges more than boxes */
g_test_add_func ("/util/boxes/onscreen-edges", test_find_onscreen_edges);
g_test_add_func ("/util/boxes/nonintersected-monitor-edges",
test_find_nonintersected_monitor_edges);
/* And now the misfit functions that don't quite fit in anywhere else... */
g_test_add_func ("/util/boxes/gravity-resize", test_gravity_resize);
g_test_add_func ("/util/boxes/closest-point-to-line",
test_find_closest_point_to_line);
}