/*
* Copyright (c) 2005 X.Org Foundation L.L.C.
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* 
* Copyright (c) Applied Testing and Technology, Inc. 1995
* All Rights Reserved.
* 
* 
* Portions of this software are based on Xlib and X Protocol Test Suite.
* We have used this material under the terms of its copyright, which grants
* free use, subject to the conditions below.  Note however that those
* portions of this software that are based on the original Test Suite have
* been significantly revised and that all such revisions are copyright (c)
* 1995 Applied Testing and Technology, Inc.  Insomuch as the proprietary
* revisions cannot be separated from the freely copyable material, the net
* result is that use of this software is governed by the ApTest copyright.
* 
* Copyright (c) 1990, 1991  X Consortium
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
* X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* 
* Except as contained in this notice, the name of the X Consortium shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from the X Consortium.
* 
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of UniSoft not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.  UniSoft
* makes no representations about the suitability of this software for any
* purpose.  It is provided "as is" without express or implied warranty.
* 
*/
/*
 * SYNOPSIS:
 *   int ((*)())()
 *   XSetErrorHandler(handler)
 *   int (*handler)();
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	"xtest.h"
#include	"X11/Xlib.h"
#include	"X11/Xutil.h"
#include	"X11/Xresource.h"
#include	"X11/keysym.h"
#include	"tet_api.h"
#include	"xtestlib.h"
#include	"pixval.h"
#ifdef INPUTEXTENSION
#include        "X11/extensions/XInput.h"
#include        "XItest.h"
#endif

extern	Display	*Dsp;
extern	Window	Win;

extern	Window	ErrdefWindow;
extern	Drawable ErrdefDrawable;
extern	GC		ErrdefGC;
extern	Colormap ErrdefColormap;
extern	Pixmap	ErrdefPixmap;
extern	Atom	ErrdefAtom;
extern	Cursor	ErrdefCursor;
extern	Font	ErrdefFont;


#define T_XSetErrorHandler	1
char    *TestName = "XSetErrorHandler";

/*
 * Defines for different argument types
 */


/*
 * Arguments to the XSetErrorHandler function
 */
static int (*handler)();


static int 	ValueReturn;

#include <signal.h>
#include <sys/wait.h>
#include "X11/Xproto.h"

#define	_xcall_(rvalue)		rvalue = XSetErrorHandler(handler)

static	int	counter = 0;
static	int	lastserial = 0;
static	int	lastrequest_code = 0;

static int
errorhandler(display, errorevent)
Display *display;
XErrorEvent *errorevent;
{
	lastserial = errorevent->serial;
	lastrequest_code = errorevent->request_code;
	return(counter++);
}

static int
_errorhandler(display, errorevent)
Display *display;
XErrorEvent *errorevent;
{
	return(counter--);
}



#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>

#define	MESSBUF	55


int 	tet_thistest;

/*
 * Called at the beginning of each test purpose to reset the
 * arguments to their initial values
 */
static void
setargs()
{
	handler = 0;
}

/*
 * Set the arguments to default values for error tests
 */
static void
seterrdef()
{
}

static void t001(){

int	oldcounter;
Window	w;
int	(*proc)();
Display	*display = Dsp;
int 	pass = 0, fail = 0;

 	report_purpose(1);

	report_assertion("Assertion XSetErrorHandler-1.(A)");
	report_assertion("A call to XSetErrorHandler sets the error handler to");
	report_assertion("handler.");

	report_strategy("Call XSetErrorHandler to set error handler to errorhandler.");
	report_strategy("Generate an error.");
	report_strategy("Verify that errorhandler was called.");

	tpstartup();
	setargs();
/* Call XSetErrorHandler to set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Generate an error. */
	w = badwin(display);
	oldcounter = counter;
	XDestroyWindow(display, w);
	XSync(display, True);
/* Verify that errorhandler was called. */
	/* assume that if it was not called it was not set... */
	if (counter == oldcounter) {
		report("Error handler not set.");
		FAIL;
	}
	else
		CHECK;
	CHECKPASS(1);
	tpcleanup();
	pfcount(pass, fail);
}

static void t002(){

int	(*proc)();
int 	pass = 0, fail = 0;

 	report_purpose(2);

	report_assertion("Assertion XSetErrorHandler-2.(A)");
	report_assertion("A call to XSetErrorHandler returns the previous error");
	report_assertion("handler.");

	report_strategy("Call XSetErrorHandler to set error handler to errorhandler.");
	report_strategy("Call XSetErrorHandler to set error handler to _errorhandler.");
	report_strategy("Verify that errorhandler was returned.");
	report_strategy("Call XSetErrorHandler to set error handler to errorhandler.");
	report_strategy("Verify that _errorhandler was returned.");

	tpstartup();
	setargs();
/* Call XSetErrorHandler to set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Call XSetErrorHandler to set error handler to _errorhandler. */
	handler = _errorhandler;
	_xcall_(proc);
/* Verify that errorhandler was returned. */
	if (proc != errorhandler) {
		report("Returned 0x%x, expected 0x%x", proc, errorhandler);
		FAIL;
	}
	else
		CHECK;
/* Call XSetErrorHandler to set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Verify that _errorhandler was returned. */
	if (proc != _errorhandler) {
		report("Returned 0x%x, expected 0x%x", proc, _errorhandler);
		FAIL;
	}
	else
		CHECK;
	CHECKPASS(2);
	tpcleanup();
	pfcount(pass, fail);
}

/* Including from file Mdefcode.tmc.1104 */
static void t003(){

int 	pass = 0, fail = 0;

 	report_purpose(3);

	report_assertion("Assertion XSetErrorHandler-3.(B)");
	report_assertion("A call to XSetErrorHandler with handler set to NULL sets");
	report_assertion("the error handler to the default error handler.");
	report_assertion("Reason for omission: There is no known portable test method for this assertion");

	report_strategy("Report UNTESTED");

	tpstartup();
	setargs();
	UNTESTED;
	tpcleanup();
	pfcount(pass, fail);
}

/* End of included file Mdefcode.tmc.1104 */

static void t004(){

int	(*proc)();
pid_t	child;
int	stat_loc;
int	waitstatus;
Display	*display = Dsp;
int 	p[2];
int 	gotmessage = 0;
char	buf[MESSBUF];
FILE	*fp;
int 	pass = 0, fail = 0;

 	report_purpose(4);

	report_assertion("Assertion XSetErrorHandler-4.(A)");
	report_assertion("The default error handler prints a message and exits.");

	report_strategy("Get default error handler.");
	report_strategy("Create child process.");
	report_strategy("Child calls default error handler and loops forever.");
	report_strategy("Parent sleeps for 10 seconds.");
	report_strategy("Parent verifies that child no longer exists.");

	tpstartup();
	setargs();
/* Get default error handler. */
	handler = (int (*)()) NULL;
	_xcall_(proc);
	/* requires two calls! */
	_xcall_(proc);

	if (pipe(p) == -1) {
		delete("Could not create pipe");
		return;
	}

/* Create child process. */
	child = fork();
	if (!child) {
		XErrorEvent	event;
		event.error_code = BadWindow;

		close(p[0]);
		/*
		 * Capture both stdout and stderr into the pipe.
		 */
		dup2(p[1], 1);
		dup2(p[1], 2);

/* Child calls default error handler and loops forever. */
		(*proc)(display, &event);

		/*
		 * Now close the pipe to make sure that the parent will not hang.
		 */
		close(p[1]);
		close(1);
		close(2);

		for (;;)
			continue;
		/*NOTREACHED*/
	}
	else
		CHECK;

	close(p[1]);

/* Parent sleeps for 10 seconds. */
	sleep(10);

	/*
	 * Read message in reasonable size chunks.
	 */
	fp = fdopen(p[0], "r");
	if (fp == NULL) {
		delete("Could not fdopen pipe");
		return;
	}
	trace("The message produced by the default handler:");
	gotmessage = 0;
	while (fgets(buf, MESSBUF-1, fp)) {
		gotmessage = 1;
		buf[MESSBUF-1] = '\0';
		trace("Message: %s", buf);
	}

	if (!gotmessage) {
		report("No message was printed");
		FAIL;
	} else
		CHECK;

/* Parent verifies that child no longer exists. */
	waitstatus = waitpid(child, &stat_loc, WNOHANG);
	if (waitstatus != child) {
		report("Child did not exit.");
		FAIL;
		kill(child, SIGKILL);
		waitpid(child, &stat_loc, WNOHANG);
	}
	else
		CHECK;
	CHECKPASS(3);
	tpcleanup();
	pfcount(pass, fail);
}

static void t005(){

int	(*proc)();
int	i;
int 	pass = 0, fail = 0;

 	report_purpose(5);

	report_assertion("Assertion XSetErrorHandler-5.(B)");
	report_assertion("There is no limit to the number of times XSetErrorHandler");
	report_assertion("may be called.");
	report_assertion("Reason for omission: Testing the assertion would require an unreasonable amount of time or resources on most systems");

	report_strategy("Set handler to errorhandler.");
	report_strategy("Call XSetErrorHandler 1000 times.");
	report_strategy("Report untested.");

	tpstartup();
	setargs();
/* Set handler to errorhandler. */
	handler = errorhandler;
/* Call XSetErrorHandler 1000 times. */
	for (i=0; i<1000; i++) {
		if (i == 0)
			CHECK;
		startcall(Dsp);
		if (isdeleted())
			return;
		proc = XSetErrorHandler(handler);
		endcall(Dsp);
		if (geterr() != Success) {
			report("Got %s, Expecting Success", errorname(geterr()));
			FAIL;
		}
	}
/* Report untested. */
	CHECKUNTESTED(1);
	tpcleanup();
	pfcount(pass, fail);
}

static void t006(){

int	(*proc)();
Display	*display = Dsp;
int	oldcounter;
int	status;
XFontStruct	*font_struct;
Colormap	colormap;
XColor	exact_def, screen_def;
int 	pass = 0, fail = 0;

 	report_purpose(6);

	report_assertion("Assertion XSetErrorHandler-6.(A)");
	report_assertion("When a BadName error occurs from a call to XLoadQueryFont,");
	report_assertion("XLookupColor, or XAllocNamedColor, then handler is not");
	report_assertion("called.");

	report_strategy("Set error handler to errorhandler.");
	report_strategy("Generate a BadName error through a call to XLoadQueryFont.");
	report_strategy("Verify that XLoadQueryFont returned NULL.");
	report_strategy("Verify that errorhandler was not called.");
	report_strategy("Generate a BadName error through a call to XLookupColor.");
	report_strategy("Verify that XLookupColor returned 0.");
	report_strategy("Verify that errorhandler was not called.");
	report_strategy("Generate a BadName error through a call to XAllocNamedColor.");
	report_strategy("Verify that XAllocNamedColor returned 0.");
	report_strategy("Verify that errorhandler was not called.");

	tpstartup();
	setargs();
/* Set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Generate a BadName error through a call to XLoadQueryFont. */
	oldcounter = counter;
	font_struct = XLoadQueryFont(display, config.bad_font_name);
	XSync(display, True);
/* Verify that XLoadQueryFont returned NULL. */
	if (font_struct != (XFontStruct *) NULL) {
		delete("XLoadQueryFont did not return NULL.");
		XFreeFont(display, font_struct);
		return;
	}
	else
		CHECK;
/* Verify that errorhandler was not called. */
	if (counter != oldcounter) {
		report("Error handler was called.");
		FAIL;
	}
	else
		CHECK;
/* Generate a BadName error through a call to XLookupColor. */
	oldcounter = counter;
	colormap = makecolmap(display, DefaultVisual(display, DefaultScreen(display)), AllocNone);
	status = XLookupColor(display, colormap, config.bad_colorname, &exact_def, &screen_def);
	XSync(display, True);
/* Verify that XLookupColor returned 0. */
	if (status != 0) {
		delete("XLookupColor returned %d, expected 0.", status);
		return;
	}
	else
		CHECK;
/* Verify that errorhandler was not called. */
	if (counter != oldcounter) {
		report("Error handler was called.");
		FAIL;
	}
	else
		CHECK;
/* Generate a BadName error through a call to XAllocNamedColor. */
	oldcounter = counter;
	/* re-use colormap from previous test. */
	status = XAllocNamedColor(display, colormap, config.bad_colorname, &exact_def, &screen_def);
	XSync(display, True);
/* Verify that XAllocNamedColor returned 0. */
	if (status != 0) {
		delete("XAllocNamedColor returned %d, expected 0.", status);
		return;
	}
	else
		CHECK;
/* Verify that errorhandler was not called. */
	if (counter != oldcounter) {
		report("Error handler was called.");
		FAIL;
	}
	else
		CHECK;
	CHECKPASS(6);
	tpcleanup();
	pfcount(pass, fail);
}

static void t007(){

int	(*proc)();
Display	*display = Dsp;
int	oldcounter;
Font	font;
XFontStruct	*font_struct;
int 	pass = 0, fail = 0;

 	report_purpose(7);

	report_assertion("Assertion XSetErrorHandler-7.(A)");
	report_assertion("When a BadFont error occurs from a QueryFont protocol");
	report_assertion("request, then handler is not called.");

	report_strategy("Set error handler to errorhandler.");
	report_strategy("Create a bad font ID.");
	report_strategy("Call XQueryFont to generate a BadFont error.");
	report_strategy("Verify that XQueryFont returned NULL.");
	report_strategy("Verify that errorhandler was not called.");

	tpstartup();
	setargs();
/* Set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Create a bad font ID. */
	font = badfont(display);
/* Call XQueryFont to generate a BadFont error. */
	oldcounter = counter;
	font_struct = XQueryFont(display, font);
	XSync(display, True);
/* Verify that XQueryFont returned NULL. */
	if (font_struct != (XFontStruct *) NULL) {
		delete("XQueryFont did not return NULL.");
		XFreeFont(display, font_struct);
		return;
	}
	else
		CHECK;
/* Verify that errorhandler was not called. */
	if (counter != oldcounter) {
		report("Error handler was called.");
		FAIL;
	}
	else
		CHECK;
	CHECKPASS(2);
	tpcleanup();
	pfcount(pass, fail);
}

static void t008(){

int	(*proc)();
Display	*display = Dsp;
int	oldcounter;
Window	w;
unsigned long	nextrequest;
int 	pass = 0, fail = 0;

 	report_purpose(8);

	report_assertion("Assertion XSetErrorHandler-8.(A)");
	report_assertion("On a call to handler, the serial member in the XErrorEvent");
	report_assertion("structure is set to the number that was the value of");
	report_assertion("NextRequest immediately before the protocol request was");
	report_assertion("sent.");

	report_strategy("Call XSetErrorHandler to set error handler to errorhandler.");
	report_strategy("Create window.");
	report_strategy("Destroy window.");
	report_strategy("Call NextRequest to get the serial number to be used in the next request.");
	report_strategy("Call XDestroyWindow to generate a BadWindow error.");
	report_strategy("Verify that errorhandler was called.");
	report_strategy("Verify that the serial member in the XErrorEvent structure");
	report_strategy("was set correctly.");

	tpstartup();
	setargs();
/* Call XSetErrorHandler to set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Create window. */
	w = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, 5, 5, 0, 0, 0);
/* Destroy window. */
	XDestroyWindow(display, w);
	XSync(display, True);
/* Call NextRequest to get the serial number to be used in the next request. */
	nextrequest = NextRequest(display);
/* Call XDestroyWindow to generate a BadWindow error. */
	oldcounter = counter;
	XDestroyWindow(display, w);
	XSync(display, True);
/* Verify that errorhandler was called. */
	if (counter == oldcounter) {
		delete("Error handler was not called.");
		return;
	}
	else
		CHECK;
/* Verify that the serial member in the XErrorEvent structure */
/* was set correctly. */
	if (nextrequest != lastserial) {
		report("Returned %d, expected %d", lastserial, nextrequest);
		FAIL;
	}
	else
		CHECK;
	CHECKPASS(2);
	tpcleanup();
	pfcount(pass, fail);
}

static void t009(){

int	(*proc)();
Display	*display = Dsp;
int	oldcounter;
Window	w;
int 	pass = 0, fail = 0;

 	report_purpose(9);

	report_assertion("Assertion XSetErrorHandler-9.(A)");
	report_assertion("On a call to handler, the request_code member in the");
	report_assertion("XErrorEvent structure is set to the protocol request of the");
	report_assertion("procedure that failed.");

	report_strategy("Call XSetErrorHandler to set error handler to errorhandler.");
	report_strategy("Create window.");
	report_strategy("Destroy window.");
	report_strategy("Call XDestroyWindow to generate a BadWindow error.");
	report_strategy("Verify that errorhandler was called.");
	report_strategy("Verify that the request_code member in the XErrorEvent structure");
	report_strategy("was set correctly.");

	tpstartup();
	setargs();
/* Call XSetErrorHandler to set error handler to errorhandler. */
	handler = errorhandler;
	_xcall_(proc);
/* Create window. */
	w = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, 5, 5, 0, 0, 0);
/* Destroy window. */
	XDestroyWindow(display, w);
	XSync(display, True);
/* Call XDestroyWindow to generate a BadWindow error. */
	oldcounter = counter;
	/* make sure that it does not already equal X_DestroyWindow */
	lastrequest_code = X_DestroyWindow + 1;
	XDestroyWindow(display, w);
	XSync(display, True);
/* Verify that errorhandler was called. */
	if (counter == oldcounter) {
		delete("Error handler was not called.");
		return;
	}
	else
		CHECK;
/* Verify that the request_code member in the XErrorEvent structure */
/* was set correctly. */
	if (lastrequest_code != X_DestroyWindow) {
		report("Returned %d, expected %d", lastrequest_code, X_DestroyWindow);
		FAIL;
	}
	else
		CHECK;
	CHECKPASS(2);
	tpcleanup();
	pfcount(pass, fail);
}

/* End of Test Cases */


struct tet_testlist tet_testlist[] = {
	{ t001, 1 },
	{ t002, 2 },
	{ t003, 3 },
	{ t004, 4 },
	{ t005, 5 },
	{ t006, 6 },
	{ t007, 7 },
	{ t008, 8 },
	{ t009, 9 },
	{ NULL, 0 }
};

int 	ntests = sizeof(tet_testlist)/sizeof(struct tet_testlist)-1;

void	(*tet_startup)() = startup;
void	(*tet_cleanup)() = cleanup;
