Prettier JQuery tables
[contractdashboard.git] / media / unit_testing / unit_test.js
blob:a/media/unit_testing/unit_test.js -> blob:b/media/unit_testing/unit_test.js
--- a/media/unit_testing/unit_test.js
+++ b/media/unit_testing/unit_test.js
@@ -1,1 +1,406 @@
-
+/*
+ * File:        unit_test.js
+ * Version:     0.0.1
+ * CVS:         $Id$
+ * Description: Unit test framework
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * Created:     Sun Mar  8 22:02:49 GMT 2009
+ * Modified:    $Date$ by $Author$
+ * Language:    Javascript
+ * License:     GPL v2 or BSD 3 point style
+ * Project:     DataTables
+ * Contact:     allan.jardine@sprymedia.co.uk
+ * 
+ * Copyright 2009 Allan Jardine, all rights reserved.
+ *
+ * Description:
+ * This is a javascript library suitable for use as a unit testing framework. Employing a queuing
+ * mechanisim to take account of async events in javascript, this library will communicates with
+ * a controller frame (to report individual test status).
+ * 
+ */
+
+
+var oTest = {
+	/* Block further tests from occuring - might be end of tests or due to async wait */
+	bBlock: false,
+	
+	/* Number of times to try retesting for a blocking test */
+	iReTestLimit: 20,
+	
+	/* Amount of time to wait between trying for an async test */
+	iReTestDelay: 150,
+	
+	/* End tests - external control */
+	bEnd: false,
+	
+	/* Internal variables */
+	_aoQueue: [],
+	_iReTest: 0,
+	_bFinished: false,
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Recommened public functions
+	 */
+	
+	/*
+	 * Function: fnTest
+	 * Purpose:  Add a test to the queue
+	 * Returns:  -
+	 * Inputs:   string:sMessage - name of the test
+	 *           function:fnTest - function which will be evaludated to get the test result
+	 */
+	"fnTest": function ( sMessage, fnSetup, fnTest )
+	{
+		this._aoQueue.push( {
+			"sMessage": sMessage,
+			"fnSetup": fnSetup,
+			"fnTest": fnTest,
+			"bPoll": false
+		} );
+		this._fnNext();
+	},
+	
+	/*
+	 * Function: fnWaitTest
+	 * Purpose:  Add a test to the queue which has a re-test cycle
+	 * Returns:  -
+	 * Inputs:   string:sMessage - name of the test
+	 *           function:fnTest - function which will be evaludated to get the test result
+	 */
+	"fnWaitTest": function ( sMessage, fnSetup, fnTest )
+	{
+		this._aoQueue.push( {
+			"sMessage": sMessage,
+			"fnSetup": fnSetup,
+			"fnTest": fnTest,
+			"bPoll": true
+		} );
+		this._fnNext();
+	},
+	
+	/*
+	 * Function: fnStart
+	 * Purpose:  Indicate that this is a new unit and what it is testing (message to end user)
+	 * Returns:  -
+	 * Inputs:   string:sMessage - message to give to the user about this unit
+	 */
+	"fnStart": function ( sMessage )
+	{
+		window.parent.controller.fnStartMessage( sMessage );
+	},
+	
+	/*
+	 * Function: fnComplete
+	 * Purpose:  Tell the controller that we are all done here
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	"fnComplete": function ()
+	{
+		this._bFinished = true;
+		this._fnNext();
+	},
+	
+	/*
+	 * Function: fnCookieDestroy
+	 * Purpose:  Destroy a cookie of a given name
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	"fnCookieDestroy": function ( oTable )
+	{
+		var sName = oTable.fnSettings().sCookiePrefix+oTable.fnSettings().sInstance;
+		var aParts = window.location.pathname.split('/');
+		var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
+		document.cookie = sNameFile+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
+			aParts.join('/') + "/";
+	},
+	
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Internal functions
+	 */
+	
+	
+	"_fnReTest": function ( oTestInfo )
+	{
+		var bResult = oTestInfo.fnTest( );
+		if ( bResult )
+		{
+			/* Test passed on retry */
+			this._fnResult( true );
+			this._fnNext();
+		}
+		else
+		{
+			if ( this._iReTest < this.iReTestLimit )
+			{
+				this._iReTest++;
+				setTimeout( function() {
+					oTest._fnReTest( oTestInfo );
+				}, this.iReTestDelay );
+			}
+			else
+			{
+				this._fnResult( false );
+			}
+		}
+	},
+	
+	"_fnNext": function ()
+	{
+		if ( this.bEnd )
+		{
+			return;
+		}
+		
+		if ( !this.bBlock && this._aoQueue.length > 0 )
+		{
+			var oNextTest = this._aoQueue.shift();
+			window.parent.controller.fnTestStart( oNextTest.sMessage );
+			this.bBlock = true;
+			
+			if ( typeof oNextTest.fnSetup == 'function' )
+			{
+				oNextTest.fnSetup( );
+			}
+			var bResult = oNextTest.fnTest( );
+			//bResult = false;
+			
+			if ( oNextTest.bPoll )
+			{
+				if ( bResult )
+				{
+					this._fnResult( true );
+					this._fnNext();
+				}
+				else
+				{
+					_iReTest = 0;
+					setTimeout( function() {
+						oTest._fnReTest( oNextTest );
+					}, this.iReTestDelay );
+				}
+			}
+			else
+			{
+				this._fnResult( bResult );
+				this._fnNext();
+			}
+		}
+		else if ( !this.bBlock && this._aoQueue.length == 0 && this._bFinished )
+		{
+			window.parent.controller.fnUnitComplete( );
+		}
+	},
+	
+	"_fnResult": function ( b )
+	{
+		window.parent.controller.fnTestResult( b );
+		this.bBlock = false;
+		if ( !b )
+		{
+			this.bEnd = true;
+		}
+	}
+};
+
+
+var oDispacher = {
+	"click": function ( nNode, oSpecial )
+	{
+		var evt = this.fnCreateEvent( 'click', nNode, oSpecial );
+		if ( nNode.dispatchEvent )
+			nNode.dispatchEvent(evt);
+		else
+			nNode.fireEvent('onclick', evt);
+	},
+	
+	"change": function ( nNode )
+	{
+		var evt = this.fnCreateEvent( 'change', nNode );
+		if ( nNode.dispatchEvent )
+		nNode.dispatchEvent(evt);
+		else
+			nNode.fireEvent('onchange', evt);
+	},
+	
+	
+	/*
+	 * Function: fnCreateEvent
+	 * Purpose:  Create an event oject based on the type to trigger an event - x-platform
+	 * Returns:  event:evt
+	 * Inputs:   string:sType - type of event
+	 *           node:nTarget - target node of the event
+	 */
+	fnCreateEvent: function( sType, nTarget, oSpecial )
+	{
+		var evt = null;
+		var oTargetPos = this._fnGetPos( nTarget );
+		var sTypeGroup = this._fnEventTypeGroup( sType );
+		if ( typeof oSpecial == 'undefined' )
+		{
+			oSpecial = {};
+		}
+		
+		var ctrlKey = false;
+		var altKey = false;
+		var shiftKey = (typeof oSpecial.shift != 'undefined') ? oSpecial.shift : false;
+		var metaKey = false;
+		var button = false;
+		
+		if ( document.createEvent )
+		{
+			switch ( sTypeGroup )
+			{
+				case 'mouse':
+					evt = document.createEvent( "MouseEvents" );
+					evt.initMouseEvent( sType, true, true, window, 0, oTargetPos[0], oTargetPos[1], 
+						oTargetPos[0], oTargetPos[1], ctrlKey, altKey, shiftKey, 
+						metaKey, button, null );
+					break;
+				
+				case 'html':
+					evt = document.createEvent( "HTMLEvents" );
+					evt.initEvent( sType, true, true );
+					break;
+					
+				case 'ui':
+					evt = document.createEvent( "UIEvents" );
+					evt.initUIEvent( sType, true, true, window, 0 );
+					break;
+				
+				default:
+					break;
+			}
+		}
+		else if ( document.createEventObject )
+		{
+			switch ( sTypeGroup )
+			{
+				case 'mouse':
+					evt = document.createEventObject();
+					evt.screenX = oTargetPos[0];
+					evt.screenX = oTargetPos[1];
+					evt.clientX = oTargetPos[0];
+					evt.clientY = oTargetPos[1];
+					evt.ctrlKey = ctrlKey;
+					evt.altKey = altKey;
+					evt.shiftKey = shiftKey;
+					evt.metaKey = metaKey;
+					evt.button = button;
+					evt.relatedTarget = null;
+					break;
+				
+				case 'html':
+					/* fall through to basic event object */
+					
+				case 'ui':
+					evt = document.createEventObject();
+					break;
+				
+				default:
+					break;
+			}
+		}
+		
+		return evt;
+	},
+	
+	/* 
+	 * Function: DesignCore.fnGetPos
+	 * Purpose:  Get the position of an element on the page
+	 * Returns:  array[ 0-int:left, 1-int:top ]
+	 * Inputs:   node:obj - node to analyse
+	 */
+	_fnGetPos: function ( obj ) 
+	{
+		var curleft = 0;
+		var curtop = 0;
+		
+		if (obj.offsetParent) 
+		{
+			curleft = obj.offsetLeft;
+			curtop = obj.offsetTop;
+			while (obj = obj.offsetParent ) 
+			{
+				curleft += obj.offsetLeft;
+				curtop += obj.offsetTop;
+			}
+		}
+		return [curleft,curtop];
+	},
+	
+	
+	/*
+	 * Function: _fnEventTypeGroup
+	 * Purpose:  Group the event types as per w3c groupings
+	 * Returns:  -
+	 * Inputs:   string:sType
+	 */
+	_fnEventTypeGroup: function ( sType )
+	{
+		switch ( sType )
+		{
+			case 'click':
+			case 'dblclick':
+			case 'mousedown':
+			case 'mousemove':
+			case 'mouseout':
+			case 'mouseover':
+			case 'mouseup':
+				return 'mouse';
+			
+			case 'change':
+			case 'focus':
+			case 'blur':
+			case 'select':
+			case 'submit':
+				return 'html';
+				
+			case 'keydown':
+			case 'keypress':
+			case 'keyup':
+			case 'load':
+			case 'unload':
+				return 'ui';
+			
+			default:
+				return 'custom';
+		}
+	}
+}
+
+
+var oSession = {
+	nTable: null,
+	
+	fnCache: function ()
+	{
+		this.nTable = document.getElementById('demo').cloneNode(true);
+	},
+	
+	fnRestore: function ()
+	{
+		while( $.fn.dataTableSettings.length > 0 )
+		{
+			$.fn.dataTableSettings[0].oInstance.fnDestroy();
+		}
+		//$.fn.dataTableSettings.splice( 0, $.fn.dataTableSettings.length );
+		var nDemo = document.getElementById('demo');
+		nDemo.innerHTML = "";
+		for ( var i=0, iLen=this.nTable.childNodes.length ; i<iLen ; i++ )
+		{
+			nDemo.appendChild( this.nTable.childNodes[0] );
+		}
+		this.fnCache();
+	}
+}
+
+$(document).ready( function () {
+	oSession.fnCache();
+} );
+