/*******************************************************************************
 * _TestPubSub.js:
 *		Component of the JSUnit-based test suite for the OpenAjax Hub.
 *
 *		This is the unit test for routines having to do with managing event
 *		publishing and event subscribing. (The "event hub" or "topic bus".)
 *
 * Copyright 2006-2007 OpenAjax Alliance
 *
 * 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.
 *
 ******************************************************************************/

// FIXME: Either add tests for scope or drop the feature

var _TestPubSub_tests = [
  "t1_1_1",
  "t1_1_2",   
  "t1_1_3",
  "t1_2_1",
  "t1_3_1",
  "t2_1",
  "t2_2",
  "t3_1",
  "t4_1",
  "t4_2",
  "t4_3"
];

/************************************************************************
 * JSUnit scaffolding used by _TestPubSub_jsunit_*.html files.
 * Not used for standalone (i.e., non-JSUnit) testing harness.
 ***********************************************************************/
function exposeTestFunctionNames(){
	 return ["test_PubSub"];
}
function test_PubSub() {
	for (var i = 0; i < _TestPubSub_tests.length; i++) {
		OpenAjax.hub.reinit();
		var test = window[_TestPubSub_tests[i]];
		test.run();
		assertTrue(test.details, test.pass);
	}
}
/********************** End of JSUnit scaffolding. **********************/


/*************************************************************************
 * Standalone testing scaffolding used by _TestPubSub_standalone.html
 ************************************************************************/
function runTests() {
	var result = '';
	for (var i = 0; i < _TestPubSub_tests.length; i++) {
		OpenAjax.hub.reinit();
		var test = window[_TestPubSub_tests[i]];
		test.run();
		if(test.pass) 
			result += (_TestPubSub_tests[i] + ': <font color="blue">PASS</font><br/>');
		else {
			result += (_TestPubSub_tests[i] + ': <font color="red"><strong>FAIL</strong></font><br/>');

			var report = '';
			var passing = true;
			for (var i = 0; i < test.result.length; i++) {
				if(passing) {
					if(test.result[i] != test.expectedResult[i]) {
						passing = false;
						report += "<strong>";						
					}
				}
				report += test.result[i];
			}
			if(!passing) {
				report += "</strong>";
			}
			result += ('<hr/><br/>ACTUAL: <br/>' + report + '<hr/><br/>EXPECTEDL:<br/>' + test.expectedResult + '<hr/><br/>');
		}
	}
document.write(result);
}
function ShowValue(val)
{
        var testFrame = document.getElementById("myFrame");
        var doc = testFrame.contentDocument;
        if (doc == undefined || doc == null) 
            doc = testFrame.contentWindow.document;

        doc.open();
        doc.write(val);
        doc.close();
    
}
/************* End of standalone testing scaffolding.********************/


/************************************************************************
 * Unit tests.
 ***********************************************************************/

var t1_1_1 = {
	name: "1.1.1", 
	description: "Publish unit tests",
	result: "",
	expectedResult: "1.1.1: start, OK: will publish to nobody, OK: published to nobody, "
}
t1_1_1.run = function() {
	this.result = "1.1.1: start, ";
	
	try {
		this.result += "OK: will publish to nobody, ";	
		this.sub0 = OpenAjax.hub.publish("example.event", {});
		this.result += "OK: published to nobody, ";	
	}
	catch(err) {		
		this.result += "ERROR: Error occurred when publishing to nobody: " + err.message + ", ";	
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}

var t1_1_2 = {
	name: "1.1.2", 
	description: "Subscribe unit tests: subscriberData",
	result: "",
	expectedResult: "1.1.2: start, subscribed to example.event (cb0), subscribed to example.event (cb1), publish to example.event, cb0: example.event, [object Object], null, cb1: example.event, [object Object], mySubscriberData, published to example.event, "
}
t1_1_2.cb0 = function(event, message, subscriberData) {
	t1_1_2.result += ("cb0: " + event + ", " + message + ", " + subscriberData + ", ");
	return;
}

t1_1_2.cb1 = function(event, message, subscriberData) {
	t1_1_2.result += ("cb1: " + event + ", " + message + ", " + subscriberData + ", ");
	return;
}

t1_1_2.run = function() {
	this.result = "1.1.2: start, ";
	
	this.sub0 = OpenAjax.hub.subscribe("example.event", this.cb0, null, null, null);
	this.result += "subscribed to example.event (cb0), ";	
	this.sub1 = OpenAjax.hub.subscribe("example.event", this.cb1, null, "mySubscriberData", null);
	this.result += "subscribed to example.event (cb1), ";
	this.result += "publish to example.event, ";
	OpenAjax.hub.publish("example.event", {});
	this.result += "published to example.event, ";
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}


////////////////////////////////////////////////////////////////////////////////////

var t1_1_3 = {
	name: "1.1.3",
	description: "Subscribe unit tests: callback",
	clos: { invoked: false },
	sub0: null,
	result: "",
	expectedResult: "1.1.3: start, OK: subscribed, OK: publish, OK: cb: got the correct subscriberData, OK: published, "

}

t1_1_3.cb = function(event, message, subscriberData) {
	subscriberData.result += ("OK: cb: got the correct subscriberData, ");
	return;
}

t1_1_3.run = function() {
	this.result = "1.1.3: start, ";
 	
 	this.sub0 = OpenAjax.hub.subscribe("example.event", this.cb, null, this, null);
	this.result += ("OK: subscribed, ");
	this.result += ("OK: publish, ");
 	OpenAjax.hub.publish("example.event", {});
	this.result += ("OK: published, ");
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}


var t1_2_1 = {
	name: "1.2.1",
	description: "Event unit tests",
	sub: null,
	events: [
		{ s: "abc", p: "abc", ex: false, ok: true },
		{ s: "abc", p: "def", ex: false, ok: false },
		{ s: "abc", p: "ab", ex: false, ok: false },
		{ s: "*", p: "abc", ex: false, ok: true },
		{ s: "**", p: "abc", ex: false, ok: true },
		{ s: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", p: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ex: false, ok: true },
		{ s: "**", p: "abc.def.ghi", ex: false, ok: true },
		{ s: "*", p: "abc.def", ex: false, ok: false },
		{ s: "a", p: "a", ex: false, ok: true },
		{ s: "**", p: "abc", ex: false, ok: true },
		{ s: "com.tibco", p: "com.tibco", ex: false, ok: true },
		{ s: "com.*", p: "com.tibco", ex: false, ok: true },
		{ s: "*.tibco", p: "com.tibco", ex: false, ok: true },
		{ s: "*.*", p: "com.tibco", ex: false, ok: true },
		{ s: "*.**", p: "com.tibco", ex: false, ok: true },
		{ s: "com.tibco", p: "com.tibco.foo", ex: false, ok: false },
		{ s: "com.tibco", p: "com", ex: false, ok: false },
		{ s: "com.tibco", p: "com.tibco", ex: false, ok: true },
		{ s: "a.b.c", p: "a.b.c", ex: false, ok: true },
		{ s: "a.b.*", p: "a.b.c", ex: false, ok: true },
		{ s: "a.*.c", p: "a.b.c", ex: false, ok: true },
		{ s: "*.b.c", p: "a.b.c", ex: false, ok: true },
		{ s: "*.*.c", p: "a.b.c", ex: false, ok: true },
		{ s: "a.*.*", p: "a.b.c", ex: false, ok: true },
		{ s: "*.*.*", p: "a.b.c", ex: false, ok: true },
		{ s: "*.**", p: "a.b.c", ex: false, ok: true },
		{ s: "a.b.c", p: "a.b.c", ex: false, ok: true },
		{ s: "a.b.c.d.e.f.g.h.i.j", p: "a.b.c.d.e.f.g.h.i.j", ex: false, ok: true },
		{ s: "a.**", p: "a.b.c.d.e.f.g.h.i.j", ex: false, ok: true },
		{ s: "aa.*.cc.*.e.f.g.h.i.j", p: "aa.b.cc.d.e.f.g.h.i.j", ex: false, ok: true },
		{ s: "1", p: "1", ex: false, ok: true },
		{ s: "*", p: "1", ex: false, ok: true },
		{ s: "1.0", p: "1.0", ex: false, ok: true },
		{ s: "1.0.5", p: "1.0.5", ex: false, ok: true },
		{ s: "1.0.*", p: "1.0.5", ex: false, ok: true },
		{ s: "*.1.0", p: "1.1.0", ex: false, ok: true },
		{ s: "false", p: "false", ex: false, ok: true },
		{ s: "false.true", p: "false.true", ex: false, ok: true },
		{ s: "return", p: "return", ex: false, ok: true },
		{ s: "x.length", p: "x.length", ex: false, ok: true },
		{ s: "function", p: "function", ex: false, ok: true },
		{ s: "null", p: "null", ex: false, ok: true },
		{ s: "*", p: "null", ex: false, ok: true },
		{ s: "this", p: "this", ex: false, ok: true },
		{ s: "*", p: "this", ex: false, ok: true },
		{ s: "abc=", p: "abc=", ex: false, ok: true },
		{ s: "二.重.橋", p: "二.重.橋", ex: false, ok: true },
		{ s: "*.重.橋", p: "二.重.橋", ex: false, ok: true },
		{ s: "二.*.橋", p: "二.重.橋", ex: false, ok: true },
		{ s: "二.**", p: "二.重.橋", ex: false, ok: true },
		{ s: "**", p: "二.重.橋", ex: false, ok: true },
		{ s: "$", p: "$", ex: false, ok: true },
		{ s: "a/b.c/d", p: "a/b.c/d", ex: false, ok: true }, 
		{ s: "[.]", p: "[.]", ex: false, ok: true },
		{ s: "^.&", p: "^.&", ex: false, ok: true },
		{ s: "@.%.#.).(,;.A", p: "@.%.#.).(,;.A", ex: false, ok: true },
		{ s: "A.B.C", p: "a.b.c", ex: false, ok: false },
		{ s: "a.b.c", p: "A.B.C", ex: false, ok: false }


	],
	result: "",
	expectedResult: "1.2.1: start, OK: cb: abc, OK: completed 0, OK: completed 1, OK: completed 2, "+
		"OK: cb: abc, OK: completed 3, "+
		"OK: cb: abc, OK: completed 4, "+
		"OK: cb: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, "+
		"OK: completed 5, OK: cb: abc.def.ghi, OK: completed 6, OK: completed 7, OK: cb: a, "+
		"OK: completed 8, OK: cb: abc, OK: completed 9, OK: cb: com.tibco, OK: completed 10, "+
		"OK: cb: com.tibco, OK: completed 11, "+


		"OK: cb: com.tibco, OK: completed 12, OK: cb: com.tibco, OK: completed 13, OK: cb: com.tibco, "+
		"OK: completed 14, OK: completed 15, OK: completed 16, OK: cb: com.tibco, OK: completed 17, "+
		"OK: cb: a.b.c, OK: completed 18, OK: cb: a.b.c, OK: completed 19, OK: cb: a.b.c, OK: completed 20, "+
		"OK: cb: a.b.c, OK: completed 21, OK: cb: a.b.c, OK: completed 22, OK: cb: a.b.c, OK: completed 23, "+
		"OK: cb: a.b.c, OK: completed 24, OK: cb: a.b.c, OK: completed 25, OK: cb: a.b.c, OK: completed 26, "+
		"OK: cb: a.b.c.d.e.f.g.h.i.j, OK: completed 27, OK: cb: a.b.c.d.e.f.g.h.i.j, OK: completed 28, "+
		"OK: cb: aa.b.cc.d.e.f.g.h.i.j, OK: completed 29, "+


		"OK: cb: 1, OK: completed 30, OK: cb: 1, "+
		"OK: completed 31, OK: cb: 1.0, OK: completed 32, OK: cb: 1.0.5, OK: completed 33, OK: cb: 1.0.5, "+
		"OK: completed 34, OK: cb: 1.1.0, OK: completed 35, OK: cb: false, OK: completed 36, OK: cb: false.true, "+
		"OK: completed 37, OK: cb: return, OK: completed 38, OK: cb: x.length, OK: completed 39, "+
		"OK: cb: function, OK: completed 40, OK: cb: null, OK: completed 41, OK: cb: null, "+
		"OK: completed 42, OK: cb: this, OK: completed 43, OK: cb: this, OK: completed 44, OK: cb: abc=, OK: completed 45, "+
		"OK: cb: 二.重.橋, OK: completed 46, " +
		"OK: cb: 二.重.橋, OK: completed 47, " +
		"OK: cb: 二.重.橋, OK: completed 48, " +
		"OK: cb: 二.重.橋, OK: completed 49, " +
		"OK: cb: 二.重.橋, OK: completed 50, " +
		"OK: cb: $, OK: completed 51, " +
		"OK: cb: a/b.c/d, OK: completed 52, " +
		"OK: cb: [.], OK: completed 53, " +
		"OK: cb: ^.&, OK: completed 54, " +
		"OK: cb: @.%.#.).(,;.A, OK: completed 55, " +
		"OK: completed 56, "  +
		"OK: completed 57, "


}

t1_2_1.cb = function(event, message, subscriberData) {
	subscriberData.result += ("OK: cb: " + event + ", ");
	return;
}

t1_2_1.run = function() {
	this.result = "1.2.1: start, ";

	var i;
	for(i = 0; i < this.events.length; i++) {
		try { 
			this.sub = null;
			this.sub = OpenAjax.hub.subscribe(this.events[i].s, this.cb, null, this, null);
			OpenAjax.hub.publish(this.events[i].p, {});
			OpenAjax.hub.unsubscribe(this.sub);
			this.sub = null;
			if(this.events[i].ex == false)
				this.result += ("OK: completed " + i + ", ");
			else
				this.result += ("ERROR: subscribe should have failed on " + i + ", ");
		}
		catch(err) {
			if(this.events[i].ex == true)
				this.result += ("OK: expected exception on iteration " + i + ": " + err.message + ", ");
			else
				this.result += ("ERROR: on iteration " + i + ": " + err.message + ", ");
			if(this.sub != null)
				OpenAjax.hub.unsubscribe(this.sub);
		}
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}


////////////////////////////////////////////////////////////////////////////////////

var t1_3_1 = {
	name: "1.3.1",
	description: "Multiple subscriptions",
	sub: [],
	result: "",
	expectedResult: "1.3.1: start, OK: setup: completed, OK: 13 subscribed B.B.B.X.Y, OK: cb: B.B.B.X.Y, OK: published B.B.B.X.Y, OK: unsubscribed 13, OK: cb: B.B.B, OK: published B.B.B (expect to have received callback), OK: 13 subscribed B.B.B.M.N, OK: 14 subscribed B.B.B.M.P, OK: unsubscribed 13, OK: cb: B.B.B.M.P, OK: published B.B.B.M.P (expect to have received callback), OK: cb: B.A, OK: published B.A, OK: 15 and 16 subscribed A.A.A, OK: cb: A.A.A, OK: cb: A.A.A#1, OK: cb: A.A.A#2, OK: published to A.A.A (expect to have gotten 3 callbacks), OK: unsubscribed 15, OK: cb: A.A.A, OK: cb: A.A.A#2, OK: published to A.A.A (expect to have gotten 2 callbacks), OK: unsubscribed 2, OK: cb: A.A.A#2, OK: published to A.A.A (expect to have gotten 1 callback), OK: unsubscribed 16, OK: published to A.A.A (expect to have gotten ZERO callbacks), "
}
t1_3_1.cb = function(event, message, subscriberData) {
	if(subscriberData == "B.B.B.X.Y") {
		// created the leaf subscription
		t1_3_1.result += "OK: cb: B.B.B.X.Y, ";
	}
	else if(subscriberData == "B.B.B") {
		// removed the leaf subscription, peeling branch back to
		// B.B.B. The B.B.B subscription remained intact.
		t1_3_1.result += "OK: cb: B.B.B, ";
	}
	else if(subscriberData == "B.B.B.M.P") {
		// removed the leaf subscription B.B.B.M.N, peeling branch 
		// back to B.B.B.M The B.B.B.M subscription remained intact
		// because of the other subscripton to B.B.B.M.P
		t1_3_1.result += "OK: cb: B.B.B.M.P, ";
	}
	else if(subscriberData == "B.A") {
		// Tests intermediate node, rather than leaf node
		// not a leaf. 
		t1_3_1.result += "OK: cb: B.A, ";
	}
	else if((subscriberData == "A.A.A") || (subscriberData == "A.A.A#1") || (subscriberData == "A.A.A#2")) {
		// Tests intermediate node, rather than leaf node. Expect 3 callbacks
		t1_3_1.result += "OK: cb: " + subscriberData + ", ";
	}
	return;
}

t1_3_1.setup = function() {
	this.sub[0] = OpenAjax.hub.subscribe("A", this.cb, null, "A", null);
	this.sub[1] = OpenAjax.hub.subscribe("A.A", this.cb, null, "A.A", null);
	this.sub[2] = OpenAjax.hub.subscribe("A.A.A", this.cb, null, "A.A.A", null);
	this.sub[3] = OpenAjax.hub.subscribe("A.A.B", this.cb, null, "A.A.B", null);
	this.sub[4] = OpenAjax.hub.subscribe("A.B", this.cb, null, "A.B", null);
	this.sub[5] = OpenAjax.hub.subscribe("A.B.A", this.cb, null, "A.B.A", null);
	this.sub[6] = OpenAjax.hub.subscribe("A.B.B", this.cb, null, "A.B.B", null);
	this.sub[12] = OpenAjax.hub.subscribe("B.B.B", this.cb, null, "B.B.B", null);
	this.sub[11] = OpenAjax.hub.subscribe("B.B", this.cb, null, "B.B", null);
	this.sub[7] = OpenAjax.hub.subscribe("B", this.cb, null, "B", null);
	this.sub[8] = OpenAjax.hub.subscribe("B.A", this.cb, null, "B.A", null);
	this.sub[9] = OpenAjax.hub.subscribe("B.A.A", this.cb, null, "B.A.A", null);
	this.sub[10] = OpenAjax.hub.subscribe("B.A.B", this.cb, null, "B.A.B", null);
	this.sub[17] = OpenAjax.hub.subscribe("B.B.A", this.cb, null, "B.B.A", null);
	this.result += "OK: setup: completed, ";
	return;
}

t1_3_1.run = function() {
	this.result = "1.3.1: start, ";

	try {
		this.setup();
		
		// subscribe to leaf node, publish to it, unsubscribe from it
		this.sub[13] = OpenAjax.hub.subscribe("B.B.B.X.Y", this.cb, null, "B.B.B.X.Y", null);
		this.result += "OK: 13 subscribed B.B.B.X.Y, ";
		OpenAjax.hub.publish("B.B.B.X.Y", {});
		this.result += "OK: published B.B.B.X.Y, ";
		OpenAjax.hub.unsubscribe(this.sub[13]);
		this.result += "OK: unsubscribed 13, ";
	
		// publish to what is now the leaf node after the unsubscribe of its last descendant
		OpenAjax.hub.publish("B.B.B", {});
		this.result += "OK: published B.B.B (expect to have received callback), ";
	
		// subscribe to two leaf nodes on separate branches below this node
		this.sub[13] = OpenAjax.hub.subscribe("B.B.B.M.N", this.cb, null, "B.B.B.M.N", null);
		this.result += "OK: 13 subscribed B.B.B.M.N, ";
		this.sub[14] = OpenAjax.hub.subscribe("B.B.B.M.P", this.cb, null, "B.B.B.M.P", null);
		this.result += "OK: 14 subscribed B.B.B.M.P, ";
	
		// unsubscribe from one of the two leaf nodes, causing that branch to
		// be rolled back but not affecting the other branch. Then publish to
		// the other branch to confirm that it still exists.
		OpenAjax.hub.unsubscribe(this.sub[13]);
		this.result += "OK: unsubscribed 13, ";
		OpenAjax.hub.publish("B.B.B.M.P", {});
		this.result += "OK: published B.B.B.M.P (expect to have received callback), ";
		
		// Now publish to an intermediate node
		OpenAjax.hub.publish("B.A", {});
		this.result += "OK: published B.A, ";
		
		// Now create several additional subscriptions to a leaf node
		this.sub[15] = OpenAjax.hub.subscribe("A.A.A", this.cb, null, "A.A.A#1", null); // #2
		this.sub[16] = OpenAjax.hub.subscribe("A.A.A", this.cb, null, "A.A.A#2", null); // #3
		this.result += "OK: 15 and 16 subscribed A.A.A, ";
		OpenAjax.hub.publish("A.A.A", {});
		this.result += "OK: published to A.A.A (expect to have gotten 3 callbacks), ";
	
		// Unsubscribe the 2nd (middle) one
		OpenAjax.hub.unsubscribe(this.sub[15]);
		this.result += "OK: unsubscribed 15, ";
		OpenAjax.hub.publish("A.A.A", {});
		this.result += "OK: published to A.A.A (expect to have gotten 2 callbacks), ";
	
		// Unsubscribe the 1st one
		OpenAjax.hub.unsubscribe(this.sub[2]);
		this.result += "OK: unsubscribed 2, ";
		OpenAjax.hub.publish("A.A.A", {});
		this.result += "OK: published to A.A.A (expect to have gotten 1 callback), ";
	
		// Unsubscribe the 3rd (last) one
		OpenAjax.hub.unsubscribe(this.sub[16]);
		this.result += "OK: unsubscribed 16, ";
		OpenAjax.hub.publish("A.A.A", {});
		this.result += "OK: published to A.A.A (expect to have gotten ZERO callbacks), ";

		OpenAjax.hub.unsubscribe(this.sub[0]);
		OpenAjax.hub.unsubscribe(this.sub[1]);
		OpenAjax.hub.unsubscribe(this.sub[3]);
		OpenAjax.hub.unsubscribe(this.sub[4]);
		OpenAjax.hub.unsubscribe(this.sub[5]);
		OpenAjax.hub.unsubscribe(this.sub[6]);
		OpenAjax.hub.unsubscribe(this.sub[7]);
		OpenAjax.hub.unsubscribe(this.sub[8]);
		OpenAjax.hub.unsubscribe(this.sub[9]);
		OpenAjax.hub.unsubscribe(this.sub[10]);
		OpenAjax.hub.unsubscribe(this.sub[11]);
		OpenAjax.hub.unsubscribe(this.sub[12]);
		OpenAjax.hub.unsubscribe(this.sub[14]);
		OpenAjax.hub.unsubscribe(this.sub[17]);
	}
	catch(err) {
		this.result += ("ERROR: " + err.message + ", ");
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
/*
	OpenAjax.hub.reinit();
	if(this.result != this.expectedResult) 
		return ("<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>");
	else 
		return ("<test><name>" + this.name + "</name><result>PASSED</result></test>");
*/
}

////////////////////////////////////////////////////////////////////////////////////

var t2_1 = {
	name: "2.1",
	description: "Publish and subscribe tests",
	result: "",
	expectedResult: "2.1: start, OK: publish null message (expect 1 callback), OK: cb: entry and exit, OK: published null message, OK: publish empty object (expect 1 callback), OK: cb: entry and exit, OK: published empty object, OK: publish null message to nobody (expect 0 callbacks), OK: publish empty object to nobody (expect 0 callbacks), OK: publish with filter returning true (expect 1 callback), OK: filterTrue: entry and exit, OK: cb: entry and exit, OK: publish with filter returning false (expect 0 callbacks), OK: filterFalse: entry and exit, "

}

t2_1.cb = function(event, message, subscriberData) {
	t2_1.result += "OK: cb: entry and exit, ";
	return;
}


t2_1.filterTrue = function(event, message, subscriberData) {
	t2_1.result += "OK: filterTrue: entry and exit, ";
	return true;
}

t2_1.filterFalse = function(event, message, subscriberData) {
	t2_1.result += "OK: filterFalse: entry and exit, ";
	return false;
}

t2_1.run = function() {
	this.result = "2.1: start, ";

	try {
		OpenAjax.hub.subscribe("example.event.2.1", this.cb, null, null, null);
		this.result += "OK: publish null message (expect 1 callback), ";
		OpenAjax.hub.publish("example.event.2.1", null);
		this.result += "OK: published null message, ";
		this.result += "OK: publish empty object (expect 1 callback), ";
		OpenAjax.hub.publish("example.event.2.1", {});
		this.result += "OK: published empty object, ";

		this.result += "OK: publish null message to nobody (expect 0 callbacks), ";
		OpenAjax.hub.publish("example.event.2.1.2", null);
		this.result += "OK: publish empty object to nobody (expect 0 callbacks), ";
		OpenAjax.hub.publish("example.event.2.1.2", {});

		OpenAjax.hub.subscribe("example.event.2.1.3.true", this.cb, null, null, this.filterTrue);
		OpenAjax.hub.subscribe("example.event.2.1.3.false", this.cb, null, null, this.filterFalse);
		this.result += "OK: publish with filter returning true (expect 1 callback), ";
		OpenAjax.hub.publish("example.event.2.1.3.true", {});
		this.result += "OK: publish with filter returning false (expect 0 callbacks), ";
		OpenAjax.hub.publish("example.event.2.1.3.false", {});
	}
	catch(err) {
		this.result += ("ERROR: publish threw " + err.message + ", ");
	}

	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}


////////////////////////////////////////////////////////////////////////////////////




var t2_2 = {
	name: "2.2",
	description: "Publish and subscribe: wildcards",
	result: "",
	expectedResult: "2.2: start, OK: publish alef (expect 3 callbacks), OK: cb: for alef, OK: cb: for *, "+
		"OK: cb: for **, OK: publish bet (expect 2 callbacks), OK: cb: for *, OK: cb: for **, "+
		"OK: publish alef.bet (expect 6 callbacks), OK: cb: for alef.bet, OK: cb: for alef.**, "+
		"OK: cb: for *.*, OK: cb: for *.**, OK: cb: for *.** (2), OK: cb: for **, "+
		"OK: publish alef.gimel (expect 5 callbacks), OK: cb: for alef.**, OK: cb: for *.*, "+
		"OK: cb: for *.**, OK: cb: for *.** (2), OK: cb: for **, OK: publish alef.bet.gimel (expect 15 callbacks), "+
		"OK: cb: for alef.bet.gimel, OK: cb: for alef.bet.gimel (2), OK: cb: for alef.bet.*, "+
		"OK: cb: for alef.bet.**, OK: cb: for alef.*.gimel, OK: cb: for alef.*.*, OK: cb: for alef.**, "+
		"OK: cb: for *.bet.gimel, OK: cb: for *.bet.**, OK: cb: for *.*.gimel, OK: cb: for *.*.gimel (2), "+
		"OK: cb: for *.*.*, OK: cb: for *.**, OK: cb: for *.** (2), OK: cb: for **, "+
		"OK: publish alef.bet.gimel.dalet (expect 6 callbacks), OK: cb: for alef.bet.**, OK: cb: for alef.**, "+
		"OK: cb: for *.bet.**, OK: cb: for *.**, OK: cb: for *.** (2), OK: cb: for **, "+
		"OK: publish dalet.bet.gimel (expect 8 callbacks), OK: cb: for *.bet.gimel, OK: cb: for *.bet.**, "+
		"OK: cb: for *.*.gimel, "+
		"OK: cb: for *.*.gimel (2), OK: cb: for *.*.*, OK: cb: for *.**, OK: cb: for *.** (2), "+
		"OK: cb: for **, OK: publish lamed.mem.gimel (expect 6 callbacks), OK: cb: for *.*.gimel, "+
		"OK: cb: for *.*.gimel (2), OK: cb: for *.*.*, OK: cb: for *.**, OK: cb: for *.** (2), "+
		"OK: cb: for **, OK: publish alef.dalet (expect 5 callbacks), OK: cb: for alef.**, OK: cb: for *.*, "+
		"OK: cb: for *.**, OK: cb: for *.** (2), OK: cb: for **, OK: publish lamed.mem.nun.samek (expect 3 callbacks), "+
		"OK: cb: for *.**, OK: cb: for *.** (2), OK: cb: for **, "
}

t2_2.cb = function(event, message, subscriberData) {
	t2_2.result += "OK: cb: for " + subscriberData + ", ";
	return;
}

t2_2.run = function() {
	this.result = "2.2: start, ";

	try {
		OpenAjax.hub.subscribe("alef", this.cb, null, "alef", null);
		OpenAjax.hub.subscribe("alef.bet", this.cb, null, "alef.bet", null);
		OpenAjax.hub.subscribe("alef.bet.gimel", this.cb, null, "alef.bet.gimel", null);
		OpenAjax.hub.subscribe("*.bet.gimel", this.cb, null, "*.bet.gimel", null);
		OpenAjax.hub.subscribe("alef.*.gimel", this.cb, null, "alef.*.gimel", null);
		OpenAjax.hub.subscribe("alef.bet.*", this.cb, null, "alef.bet.*", null);
		OpenAjax.hub.subscribe("*.*.gimel", this.cb, null, "*.*.gimel", null);
		OpenAjax.hub.subscribe("*.*.gimel", this.cb, null, "*.*.gimel (2)", null);	// 2nd
		OpenAjax.hub.subscribe("alef.*.*", this.cb, null, "alef.*.*", null);
		OpenAjax.hub.subscribe("*.*.*", this.cb, null, "*.*.*", null);
		OpenAjax.hub.subscribe("*", this.cb, null, "*", null);
		OpenAjax.hub.subscribe("*.*", this.cb, null, "*.*", null);
		OpenAjax.hub.subscribe("alef.bet.**", this.cb, null, "alef.bet.**", null);
		OpenAjax.hub.subscribe("alef.**", this.cb, null, "alef.**", null);
		OpenAjax.hub.subscribe("**", this.cb, null, "**", null);
		OpenAjax.hub.subscribe("*.bet.**", this.cb, null, "*.bet.**", null);
		OpenAjax.hub.subscribe("alef.bet.gimel", this.cb, null, "alef.bet.gimel (2)", null);	// 2nd
		OpenAjax.hub.subscribe("*.**", this.cb, null, "*.**", null);
		OpenAjax.hub.subscribe("*.**", this.cb, null, "*.** (2)", null);		// 2nd
		OpenAjax.hub.subscribe("chet.tet.yud", this.cb, null, "chet.tet.yud", null);

		this.result += "OK: publish alef (expect 3 callbacks), ";
		OpenAjax.hub.publish("alef", null);
		this.result += "OK: publish bet (expect 2 callbacks), ";
		OpenAjax.hub.publish("bet", null);
		this.result += "OK: publish alef.bet (expect 6 callbacks), ";
		OpenAjax.hub.publish("alef.bet", null);
		this.result += "OK: publish alef.gimel (expect 5 callbacks), ";
		OpenAjax.hub.publish("alef.gimel", null);
		this.result += "OK: publish alef.bet.gimel (expect 15 callbacks), ";
		OpenAjax.hub.publish("alef.bet.gimel", null);
		this.result += "OK: publish alef.bet.gimel.dalet (expect 6 callbacks), ";
		OpenAjax.hub.publish("alef.bet.gimel.dalet", null);
		this.result += "OK: publish dalet.bet.gimel (expect 8 callbacks), ";
		OpenAjax.hub.publish("dalet.bet.gimel", null);
		this.result += "OK: publish lamed.mem.gimel (expect 6 callbacks), ";
		OpenAjax.hub.publish("lamed.mem.gimel", null);
		this.result += "OK: publish alef.dalet (expect 5 callbacks), ";
		OpenAjax.hub.publish("alef.dalet", null);
		this.result += "OK: publish lamed.mem.nun.samek (expect 3 callbacks), ";
		OpenAjax.hub.publish("lamed.mem.nun.samek", null);
	}
	catch(err) {
		this.result += ("ERROR: subscribe or publish threw " + err.message + ", ");
	}
	
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}


var t3_1 = {
	name: "3.1",
	description: "API use in callbacks",
	blockLoop: false,
	depth: 0,
	result: "",
	expectedResult: "3.1: start, " + 
		"OK: begin pub.same, OK: test the feature (expect 1 callback), OK: cbPubSame enter 1, OK: cbPubSame: will republish, OK: cbPubSame enter 2, OK: cbPubSame exit 2, OK: cbPubSame: republished, OK: cbPubSame exit 1, OK: end pub.same, " + 
		"OK: begin pub.other, OK: test the feature (expect 1 callback), OK: cbPubOther enter 1, OK: cbPubOther: will publish to other (expect 1 callback), OK: cbUpdateOther: entry and exit, OK: cbPubOther: published to other, OK: cbPubOther exit 1, OK: end pub.other, " + 
		"OK: begin sub.same, OK: confirm zero target subscribers (expect 0 callbacks), OK: Subscribed to trigger/target event, OK: test the feature (expect 1 callback), OK: cbSubSame enter 1, OK: cbSubSame: will subscribe to same, OK: cbSubSame: subscribed to same, OK: cbSubSame: confirm subscription (expect 2 callbacks), OK: cbSubSame enter 2, OK: cbSubSame exit 2, OK: cbUpdateOther: entry and exit, OK: cbSubSame: confirmed subscription, OK: cbSubSame exit 1, OK: end sub.same, " + 
		"OK: begin sub.other, OK: confirm no target subscription (expect 0 callbacks), OK: test the feature (expect 1 callback), OK: cbSubOther enter 1, OK: cbSubOther: will subscribe to other, OK: cbSubOther: subscribed to other, OK: cbSubOther: confirm subscription (expect 1 callback), OK: cbUpdateOther: entry and exit, OK: cbSubOther: confirmed subscription, OK: cbSubOther exit 1, OK: confirm target subscription (expect 1 callback), OK: cbUpdateOther: entry and exit, OK: end sub.other, " + 
		"OK: begin unsub.same, " + 
			"OK: trigger unsub 1 (expect 6 callbacks: 01@234), OK: cbUpdateOther: entry and exit: Callback 0 - Publish 1, " + 
				"OK: cbUpdateOther: entry and exit: Callback 1 - Publish 1, OK: cbUnsubSame enter [object Object] (depth=1), " + 
				"OK: cbUnsubSame: will unsubscribe same 1, OK: cbUnsubSame: unsubscribed same, OK: cbUnsubSame exit depth=1, " + 
				"OK: cbUpdateOther: entry and exit: Callback 2 - Publish 1, OK: cbUpdateOther: entry and exit: Callback 3 - Publish 1, " + 
				"OK: cbUpdateOther: entry and exit: Callback 4 - Publish 1, " + 
			"OK: trigger unsub 3 (expect 4 callbacks: 0@24), OK: cbUpdateOther: entry and exit: Callback 0 - Publish 3, OK: cbUnsubSame enter [object Object] (depth=1), OK: cbUnsubSame: will unsubscribe same 3, OK: cbUnsubSame: unsubscribed same, OK: cbUnsubSame exit depth=1, OK: cbUpdateOther: entry and exit: Callback 2 - Publish 3, OK: cbUpdateOther: entry and exit: Callback 4 - Publish 3, " + 
			"OK: trigger unsub 0 (expect 4 callbacks: 0@24), OK: cbUpdateOther: entry and exit: Callback 0 - Publish 0, OK: cbUnsubSame enter [object Object] (depth=1), OK: cbUnsubSame: will unsubscribe same 0, OK: cbUnsubSame: unsubscribed same, OK: cbUnsubSame exit depth=1, OK: cbUpdateOther: entry and exit: Callback 2 - Publish 0, OK: cbUpdateOther: entry and exit: Callback 4 - Publish 0, " + 
			"OK: trigger unsub 2 and 4 (expect 1 callback: @), OK: cbUnsubSame enter [object Object] (depth=1), OK: cbUnsubSame: will unsubscribe same 2 and 4, OK: cbUnsubSame: unsubscribed same, OK: cbUnsubSame exit depth=1, " + 
			"OK: republish for confirmation (expect 1 callback: @), OK: cbUnsubSame enter [object Object] (depth=1), OK: cbUnsubSame: subsequent call does nothing, OK: cbUnsubSame exit depth=1, OK: end unsub.same, " + 

		"OK: begin unsub.other, OK: confirm that target exists (expect 1 callback), OK: cbUpdateOther: entry and exit, OK: test the feature (expect 1 callback), OK: cbUnsubOther enter 1, OK: cbUnsubOther: will unsubscribe other, OK: cbUnsubOther: unsubscribed other, OK: cbUnsubOther exit 1, OK: republish to confirm unsubscribe (expect no callbacks), OK: end unsub.other, " + 
		"OK: begin unsub.this, OK: publish (expect callback), OK: cbUnsubThis enter 1, OK: cbUnsubThis: will unsubscribe this, OK: cbUnsubThis: unsubscribed this, OK: cbUnsubThis exit 1, OK: republish to confirm unsubscribe (expect 0 callback), OK: end unsub.this, " + 
		"OK: begin all3.same, OK: confirm zero target subscribers (expect 0 callbacks), OK: Subscribed to trigger/target event, OK: test the feature (expect 1 callback), OK: cbAll3Same enter 1, OK: cbAll3Same: will subscribe to same once, OK: cbAll3Same: subscribed to same once, OK: cbAll3Same: publish to same (expect 2 callbacks), OK: cbAll3Same enter 2, OK: cbAll3Same exit 2, OK: cbUpdateOther: entry and exit, OK: cbAll3Same: published to same, OK: cbAll3Same: unsubscribe from same, OK: cbAll3Same: unsubscribed, OK: cbAll3Same: confirm unsubscribe (expect 1 callback), OK: cbAll3Same enter 2, OK: cbAll3Same exit 2, OK: cbAll3Same: confirmed unsubscribe, OK: cbAll3Same exit 1, OK: end all3.same, " + 
		"OK: begin all3.other, OK: confirm no target subscription (expect 0 callbacks), OK: test the feature (expect 1 callback), OK: cbAll3Other enter 1, OK: cbAll3Other: will subscribe to other, OK: cbAll3Other: subscribed to other, OK: cbAll3Other: will publish to other (expect 1 callback), OK: cbUpdateOther: entry and exit, OK: cbAll3Other: published to other, OK: cbAll3Other: unsubscribe other, OK: cbAll3Other: confirm unsubscribe (expect 0 callback), OK: cbAll3Other: confirmed unsubscribe, OK: cbAll3Other exit 1, OK: confirm unsubscribe (expect 0 callbacks), OK: end all3.other, "
} 
t3_1.cbUpdateOther = function(event, message, subscriberData) {
	t3_1.result += "OK: cbUpdateOther: entry and exit, ";
	return;
}

t3_1.cbPubSame = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbPubSame enter " + t3_1.depth + ", ");
	if(!t3_1.blockLoop) {
		t3_1.blockLoop = true;
		t3_1.result += ("OK: cbPubSame: will republish, ");
		OpenAjax.hub.publish(event, {});
		t3_1.result += ("OK: cbPubSame: republished, ");
		t3_1.blockLoop = false;
	}
	t3_1.result += ("OK: cbPubSame exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbPubOther = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbPubOther enter " + t3_1.depth + ", ");
	t3_1.result += "OK: cbPubOther: will publish to other (expect 1 callback), ";
	OpenAjax.hub.publish("saratoga.pub.other.target", {});
	t3_1.result += "OK: cbPubOther: published to other, ";
	t3_1.result += ("OK: cbPubOther exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbSubSame = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbSubSame enter " + t3_1.depth + ", ");
	if(!t3_1.blockLoop) {
		t3_1.result += "OK: cbSubSame: will subscribe to same, ";
		this.subSubSameEventTarget = OpenAjax.hub.subscribe(event, subscriberData.cbUpdateOther, null, subscriberData, null);
		t3_1.result += "OK: cbSubSame: subscribed to same, ";

		t3_1.blockLoop = true;
		t3_1.result += "OK: cbSubSame: confirm subscription (expect 2 callbacks), ";
		OpenAjax.hub.publish(event, {});
		t3_1.result += "OK: cbSubSame: confirmed subscription, ";
		t3_1.blockLoop = false;
	}
	t3_1.result += ("OK: cbSubSame exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbSubOther = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbSubOther enter " + t3_1.depth + ", ");
	t3_1.result += "OK: cbSubOther: will subscribe to other, ";
	this.subSubOtherEventTarget = OpenAjax.hub.subscribe("oakland.sub.other.target", subscriberData.cbUpdateOther, null, subscriberData, null);
	t3_1.result += "OK: cbSubOther: subscribed to other, ";
	t3_1.result += "OK: cbSubOther: confirm subscription (expect 1 callback), ";
	OpenAjax.hub.publish("oakland.sub.other.target", {});
	t3_1.result += "OK: cbSubOther: confirmed subscription, ";
	t3_1.result += ("OK: cbSubOther exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbUpdateOtherDetail = function(event, message, subscriberData) {
	t3_1.result += "OK: cbUpdateOther: entry and exit: Callback " + subscriberData + " - Publish " + message + ", ";
	return;
}

t3_1.cbUnsubSame = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbUnsubSame enter " + subscriberData + " (depth=" + t3_1.depth + "), ");

	if(message == 100) {
		t3_1.result += "OK: cbUnsubSame: will unsubscribe same 2 and 4, ";	
		OpenAjax.hub.unsubscribe(t3_1.subUnsubSameEventTarget[2]);
		OpenAjax.hub.unsubscribe(t3_1.subUnsubSameEventTarget[4]);
		t3_1.subUnsubSameEventTarget[2] = null;
		t3_1.subUnsubSameEventTarget[4] = null;
		t3_1.result += "OK: cbUnsubSame: unsubscribed same, ";
	}
	else {
		if(t3_1.subUnsubSameEventTarget[message] != null) {
			t3_1.result += "OK: cbUnsubSame: will unsubscribe same " + message + ", ";	
				OpenAjax.hub.unsubscribe(t3_1.subUnsubSameEventTarget[message]);
				t3_1.subUnsubSameEventTarget[message] = null;
			t3_1.result += "OK: cbUnsubSame: unsubscribed same, ";
		}
		else {
			t3_1.result += "OK: cbUnsubSame: subsequent call does nothing, ";
		}
	}
	t3_1.result += ("OK: cbUnsubSame exit depth=" + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbUnsubOther = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbUnsubOther enter " + t3_1.depth + ", ");
	t3_1.result += "OK: cbUnsubOther: will unsubscribe other, ";
	OpenAjax.hub.unsubscribe(t3_1.subUnsubOtherTarget);
	t3_1.result += "OK: cbUnsubOther: unsubscribed other, ";
	t3_1.result += ("OK: cbUnsubOther exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbUnsubThis = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbUnsubThis enter " + t3_1.depth + ", ");
	t3_1.result += "OK: cbUnsubThis: will unsubscribe this, ";
	OpenAjax.hub.unsubscribe(t3_1.subUnsubThis);
	t3_1.result += "OK: cbUnsubThis: unsubscribed this, ";
	t3_1.result += ("OK: cbUnsubThis exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbAll3Same = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbAll3Same enter " + t3_1.depth + ", ");
	if(!t3_1.blockLoop) {
		t3_1.result += "OK: cbAll3Same: will subscribe to same once, ";
		this.subAll3SameEventTarget = OpenAjax.hub.subscribe(event, subscriberData.cbUpdateOther, null, subscriberData, null);
		t3_1.result += "OK: cbAll3Same: subscribed to same once, ";

		t3_1.blockLoop = true;
		t3_1.result += "OK: cbAll3Same: publish to same (expect 2 callbacks), ";
		OpenAjax.hub.publish(event, {});
		t3_1.result += "OK: cbAll3Same: published to same, ";
		t3_1.blockLoop = false;
		
		t3_1.result += "OK: cbAll3Same: unsubscribe from same, ";
		OpenAjax.hub.unsubscribe(this.subAll3SameEventTarget);
		t3_1.result += "OK: cbAll3Same: unsubscribed, ";

		t3_1.blockLoop = true;
		t3_1.result += "OK: cbAll3Same: confirm unsubscribe (expect 1 callback), ";
		OpenAjax.hub.publish(event, {});
		t3_1.result += "OK: cbAll3Same: confirmed unsubscribe, ";
		t3_1.blockLoop = false;		
	}
	t3_1.result += ("OK: cbAll3Same exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.cbAll3Other = function(event, message, subscriberData) {
    t3_1.depth++;
	t3_1.result += ("OK: cbAll3Other enter " + t3_1.depth + ", ");
	t3_1.result += "OK: cbAll3Other: will subscribe to other, ";
	this.subAll3OtherEventTarget = OpenAjax.hub.subscribe("losgatos.all3.other.target", subscriberData.cbUpdateOther, null, subscriberData, null);
	t3_1.result += "OK: cbAll3Other: subscribed to other, ";
	t3_1.result += "OK: cbAll3Other: will publish to other (expect 1 callback), ";
	OpenAjax.hub.publish("losgatos.all3.other.target", {});
	t3_1.result += "OK: cbAll3Other: published to other, ";
	t3_1.result += "OK: cbAll3Other: unsubscribe other, ";
	OpenAjax.hub.unsubscribe(this.subAll3OtherEventTarget);
	t3_1.result += "OK: cbAll3Other: confirm unsubscribe (expect 0 callback), ";
	OpenAjax.hub.publish("losgatos.all3.other.target", {});
	t3_1.result += "OK: cbAll3Other: confirmed unsubscribe, ";
	t3_1.result += ("OK: cbAll3Other exit " + t3_1.depth + ", ");
    t3_1.depth--;
	return;
}

t3_1.run = function() {
	this.result = "3.1: start, ";
	
	try {
		this.result += ("OK: begin pub.same, "); 
		this.subPubSameEventTrigger = OpenAjax.hub.subscribe("mountain.view.pub.same", this.cbPubSame, null, this, null);
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("mountain.view.pub.same", {});
		this.result += ("OK: end pub.same, "); 
		
		this.result += ("OK: begin pub.other, "); 
		this.subPubOtherEventTarget = OpenAjax.hub.subscribe("saratoga.pub.other.target", this.cbUpdateOther, null, this, null);
		this.subPubOtherEventTrigger = OpenAjax.hub.subscribe("sunnyvale.pub.other.trigger", this.cbPubOther, null, this, null);
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("sunnyvale.pub.other.trigger", {});
		this.result += ("OK: end pub.other, "); 
				
		this.result += ("OK: begin sub.same, "); 
		this.result += ("OK: confirm zero target subscribers (expect 0 callbacks), "); 
		OpenAjax.hub.publish("alameda.sub.same", {});
		this.result += ("OK: Subscribed to trigger/target event, "); 
		this.subSubSameEventTrigger = OpenAjax.hub.subscribe("alameda.sub.same", this.cbSubSame, null, this, null);
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("alameda.sub.same", {});
		this.result += ("OK: end sub.same, "); 
		
		this.result += ("OK: begin sub.other, "); 
		this.subSubOtherEventTarget = OpenAjax.hub.subscribe("sj.sub.other.trigger", this.cbSubOther, null, this, null);
		this.result += ("OK: confirm no target subscription (expect 0 callbacks), "); 
		OpenAjax.hub.publish("oakland.sub.other.target", {});
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("sj.sub.other.trigger", {});
		this.result += ("OK: confirm target subscription (expect 1 callback), "); 
		OpenAjax.hub.publish("oakland.sub.other.target", {});
		this.result += ("OK: end sub.other, "); 
			
		this.result += ("OK: begin unsub.same, "); 
		this.subUnsubSameEventTarget = [];

		this.subUnsubSameEventTarget[0] = OpenAjax.hub.subscribe("sf.unsub.same", this.cbUpdateOtherDetail, null, 0, null);
		this.subUnsubSameEventTarget[1] = OpenAjax.hub.subscribe("sf.unsub.same", this.cbUpdateOtherDetail, null, 1, null);
		this.subUnsubSameEventTrigger = OpenAjax.hub.subscribe("sf.unsub.same", this.cbUnsubSame, null, this, null);
		this.subUnsubSameEventTarget[2] = OpenAjax.hub.subscribe("sf.unsub.same", this.cbUpdateOtherDetail, null, 2, null);
		this.subUnsubSameEventTarget[3] = OpenAjax.hub.subscribe("sf.unsub.same", this.cbUpdateOtherDetail, null, 3, null);
		this.subUnsubSameEventTarget[4] = OpenAjax.hub.subscribe("sf.unsub.same", this.cbUpdateOtherDetail, null, 4, null);

		this.result += ("OK: trigger unsub 1 (expect 6 callbacks: 01@234), "); 
		OpenAjax.hub.publish("sf.unsub.same", 1);
		this.result += ("OK: trigger unsub 3 (expect 4 callbacks: 0@24), "); 
		OpenAjax.hub.publish("sf.unsub.same", 3);
		this.result += ("OK: trigger unsub 0 (expect 4 callbacks: 0@24), "); 
		OpenAjax.hub.publish("sf.unsub.same", 0);
		this.result += ("OK: trigger unsub 2 and 4 (expect 1 callback: @), "); 
		OpenAjax.hub.publish("sf.unsub.same", 100);
		this.result += ("OK: republish for confirmation (expect 1 callback: @), "); 
		OpenAjax.hub.publish("sf.unsub.same", 2);
		this.result += ("OK: end unsub.same, "); 

		this.result += ("OK: begin unsub.other, "); 
		this.subUnsubOtherTarget = OpenAjax.hub.subscribe("howard.unsub.other.target", this.cbUpdateOther, null, this, null);
		this.subUnsubOtherTrigger = OpenAjax.hub.subscribe("portola.unsub.other.trigger", this.cbUnsubOther, null, this, null);
		this.result += ("OK: confirm that target exists (expect 1 callback), "); 
		OpenAjax.hub.publish("howard.unsub.other.target", {});
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("portola.unsub.other.trigger", {});
		this.result += ("OK: republish to confirm unsubscribe (expect no callbacks), "); 		
		OpenAjax.hub.publish("howard.unsub.other.target", {});
		this.result += ("OK: end unsub.other, "); 
	
		this.result += ("OK: begin unsub.this, "); 
		this.subUnsubThis = OpenAjax.hub.subscribe("paloalto.unsub.this", this.cbUnsubThis, null, this, null);
		this.result += ("OK: publish (expect callback), "); 
		OpenAjax.hub.publish("paloalto.unsub.this", {});
		this.result += ("OK: republish to confirm unsubscribe (expect 0 callback), "); 
		OpenAjax.hub.publish("unsub.this", {});
		this.result += ("OK: end unsub.this, "); 

		this.result += ("OK: begin all3.same, "); 
		this.result += ("OK: confirm zero target subscribers (expect 0 callbacks), "); 
		OpenAjax.hub.publish("losaltos.all3.same", {});
		this.result += ("OK: Subscribed to trigger/target event, "); 
		this.subSubSameEventTrigger = OpenAjax.hub.subscribe("losaltos.all3.same", this.cbAll3Same, null, this, null);
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("losaltos.all3.same", {});
		this.result += ("OK: end all3.same, "); 
		
		this.result += ("OK: begin all3.other, "); 
		this.subSubOtherEventTarget = OpenAjax.hub.subscribe("monterey.all3.other.trigger", this.cbAll3Other, null, this, null);
		this.result += ("OK: confirm no target subscription (expect 0 callbacks), "); 
		OpenAjax.hub.publish("losgatos.all3.other.target", {});
		this.result += ("OK: test the feature (expect 1 callback), "); 
		OpenAjax.hub.publish("monterey.all3.other.trigger", {});
		this.result += ("OK: confirm unsubscribe (expect 0 callbacks), "); 
		OpenAjax.hub.publish("losgatos.all3.other.target", {});
		this.result += ("OK: end all3.other, "); 
	}
	catch(err) {
		this.result += ("ERROR: exception " + err.message + ", ");		
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}

var t4_1 = {
	name: "4.1",
	description: "test scope parameter",
	result: "",
	expectedResult: "4.1: start, OK: subscribed, OK: cb: example.subject, 4.1, undefined, OK: cb: example.subject, 4.1, null, OK: cb: example.subject, 4.1, subdata, OK: published, "
}

t4_1.cb = function(subject, message, subscriberData) {
	if (!this.name) {
		t4_1.result += ("cb: ERROR. no name property on this object, ");
	} else if (this.name != "4.1") {
		t4_1.result += ("cb: ERROR. incorrect value for this.name. value was: "+this.name+", ");
	} else {
		t4_1.result += ("OK: cb: " + subject + ", " + message + ", " + subscriberData + ", ");
	}
	return;
}

t4_1.run = function() {
	this.result = "4.1: start, ";
	OpenAjax.hub.subscribe("example.subject", this.cb, this);
	OpenAjax.hub.subscribe("example.subject", this.cb, this, null); 
	OpenAjax.hub.subscribe("example.subject", this.cb, this, "subdata"); 
	this.result += "OK: subscribed, "; 
	try {		
		OpenAjax.hub.publish("example.subject", "4.1");
		this.result += ("OK: published, "); 
	}
	catch(err) {
		this.result += ("ERROR: publish should not be OK, "); 
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}

var t4_2 = {
	name: "4.2",
	description: "test refOrName as string",
	result: "",
	expectedResult: "4.2: start, OK: subscribed, OK: t4_2_cb1: example.subject, 4.2, OK: t4_2_cb1: example.subject, 4.2, OK: t4_2_cb1: example.subject, 4.2, OK: t4_2.cb2: example.subject, 4.2, OK: t4_2_cb3b: example.subject, 4.2, OK: t4_2.cb4b: example.subject, 4.2, OK: published, "
}
// Note that this callback is a property of "window" object
t4_2_cb1 = function(subject, message, subscriberData) {
	t4_2.result += ("OK: t4_2_cb1: " + subject + ", " + message + ", ");
	return;
}
// Note that this callback is a property of "t4_2" object
t4_2.cb2 = function(subject, message, subscriberData) {
	t4_2.result += ("OK: t4_2.cb2: " + subject + ", " + message + ", ");
	return;
}
// Note that this callback is a property of "window" object
t4_2_cb3a = function(subject, message, subscriberData) {
	t4_2.result += ("ERROR: original t4_2_cb3a function should not get invoked, ");
	return;
}
t4_2_cb3b = function(subject, message, subscriberData) {
	t4_2.result += ("OK: t4_2_cb3b: " + subject + ", " + message + ", ");
	return;
}
// Note that this callback is a property of "t4_2" object
t4_2.cb4a = function(subject, message, subscriberData) {
	t4_2.result += ("ERROR: original t4_2.cb4a function should not get invoked, ");
	return;
}
t4_2.cb4b = function(subject, message, subscriberData) {
	t4_2.result += ("OK: t4_2.cb4b: " + subject + ", " + message + ", ");
	return;
}

t4_2.run = function() {
	this.result = "4.2: start, ";
	OpenAjax.hub.subscribe("example.subject", "t4_2_cb1");
	OpenAjax.hub.subscribe("example.subject", "t4_2_cb1", null);
	OpenAjax.hub.subscribe("example.subject", "t4_2_cb1", window);
	OpenAjax.hub.subscribe("example.subject", "cb2", this);
	// The following two subscriptions will verify late binding.
	// The function definitions will change after subscribe() is called.
	OpenAjax.hub.subscribe("example.subject", "t4_2_cb3a");
	OpenAjax.hub.subscribe("example.subject", "cb4a", this);
	// This is where the function definitions are changed.
	t4_2_cb3a = t4_2_cb3b;
	t4_2.cb4a = t4_2.cb4b;
	this.result += "OK: subscribed, "; 
	try {		
		OpenAjax.hub.publish("example.subject", "4.2");
		this.result += ("OK: published, "); 
	}
	catch(err) {
		this.result += ("ERROR: publish should not be OK, "); 
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}

var t4_3 = {
	name: "4.3",
	description: "test filter function as string",
	result: "",
	expectedResult: "4.3: start, OK: subscribed, OK: t4_3_fcb1: example.subject, 4.3, OK: t4_3.cb: example.subject, 4.3, OK: t4_3_fcb1: example.subject, 4.3, OK: t4_3.cb: example.subject, 4.3, OK: t4_3.fcb2: example.subject, 4.3, OK: t4_3.cb: example.subject, 4.3, OK: t4_3_fcb3b: example.subject, 4.3, OK: t4_3.cb: example.subject, 4.3, OK: t4_3.fcb4b: example.subject, 4.3, OK: t4_3.cb: example.subject, 4.3, OK: published, "
}
// Note that this callback is a property of "t4_3" object
t4_3.cb = function(subject, message, subscriberData) {
	t4_3.result += ("OK: t4_3.cb: " + subject + ", " + message + ", ");
	return;
}
// Note that this callback is a property of "window" object
t4_3_fcb1 = function(subject, message, subscriberData) {
	t4_3.result += ("OK: t4_3_fcb1: " + subject + ", " + message + ", ");
	return true;
}
// Note that this callback is a property of "t4_3" object
t4_3.fcb2 = function(subject, message, subscriberData) {
	t4_3.result += ("OK: t4_3.fcb2: " + subject + ", " + message + ", ");
	return true;
}
// Note that this callback is a property of "window" object
t4_3_fcb3a = function(subject, message, subscriberData) {
	t4_3.result += ("ERROR: original t4_3_fcb3a function should not get invoked, ");
	return true;
}
t4_3_fcb3b = function(subject, message, subscriberData) {
	t4_3.result += ("OK: t4_3_fcb3b: " + subject + ", " + message + ", ");
	return true;
}
// Note that this callback is a property of "t4_3" object
t4_3.fcb4a = function(subject, message, subscriberData) {
	t4_3.result += ("ERROR: original t4_3.fcb4a function should not get invoked, ");
	return true;
}
t4_3.fcb4b = function(subject, message, subscriberData) {
	t4_3.result += ("OK: t4_3.fcb4b: " + subject + ", " + message + ", ");
	return true;
}

t4_3.run = function() {
	this.result = "4.3: start, ";
	OpenAjax.hub.subscribe("example.subject", this.cb, null, null, "t4_3_fcb1");
	OpenAjax.hub.subscribe("example.subject", this.cb, window, null, "t4_3_fcb1");
	OpenAjax.hub.subscribe("example.subject", this.cb, this, null, "fcb2");
	// The following two subscriptions will verify late binding.
	// The function definitions will change after subscribe() is called.
	OpenAjax.hub.subscribe("example.subject", this.cb, null, null, "t4_3_fcb3a");
	OpenAjax.hub.subscribe("example.subject", this.cb, this, null, "fcb4a");
	// This is where the function definitions are changed.
	t4_3_fcb3a = t4_3_fcb3b;
	t4_3.fcb4a = t4_3.fcb4b;
	this.result += "OK: subscribed, "; 
	try {		
		OpenAjax.hub.publish("example.subject", "4.3");
		this.result += ("OK: published, "); 
	}
	catch(err) {
		this.result += ("ERROR: publish should not be OK, "); 
	}
	if (this.result == this.expectedResult) {
		this.pass = true;
		this.details = "<test><name>" + this.name + "</name><result>PASSED</result></test>";
	} else {
		this.pass = false;
		this.details = "<test><name>" + this.name + "</name><result>FAILED</result><details>" + this.result + "</details><expected>" + this.expectedResult + "</expected></test>";
	}
}


