LSL Protocol/Restrained Life Relay/How to Test/Relay Test 01

== Objections ==
* Ensure the relay is basically working by testing the simple version commands
* Ensure that only one relay is active during the following tests
== Instructions ==
# Rez a box with the below code in world
# Make sure you are only using one relay
# Click it and wait
# Look for "PASS:" and "FAIL:" lines
== Code ==
integer CHANNEL_RELAY = -1812221819; // Relay Channel
integer CHANNEL_VIEWER = 1812221819; // avatars cannot speak on negative channels
integer INDEX_RELAY_VERSION = 0;
integer INDEX_RELAY_IMPLVERSION = 1;
integer INDEX_RELAY_RLV_VERSION = 2;
integer INDEX_RLV_VERSION = 3;
list RESPONSE_NAMES = ["!version,xxxx", "!implversion", "@version,ok", "@version viewer reply"];
list waitFor;
// handles a response from the viewer
handleRLVResponse(string message)
{
 if (llSubStringIndex(message, "Restrained") > -1)
 {
 gotMessage(INDEX_RLV_VERSION);
 }
}
// handles a response from the relay
handleRelayResponse(string message)
{
 list tokens = llParseString2List(message, [","], []);
 string question = llList2String(tokens, 2);
 string response = llList2String(tokens, 3);
 if (question == "!version")
 {
 integer version = (integer) response;
 if (version < 1000)
 {
 llSay(0, "FAIL: Illegal response to !version: " + response);
 }
 gotMessage(INDEX_RELAY_VERSION);
 }
 else if (question == "!implversion")
 {
 if (llStringLength(response) < 3)
 {
 llSay(0, "FAIL: Response to !implversion is too short");
 }
 gotMessage(INDEX_RELAY_IMPLVERSION);
 }
 else if (question == "@version=" + (string) CHANNEL_VIEWER)
 {
 if (response != "ok")
 {
 llSay(0, "FAIL: Relay Response to @version is not \"ok\" but: " + response);
 }
 gotMessage(INDEX_RELAY_RLV_VERSION);
 }
}
// checks whether we are still waiting for this kind of response and remembers it
gotMessage(integer index)
{
 integer expected = llList2Integer(waitFor, index);
 if (!expected)
 {
 llSay(0, "FAIL: Got unexpected message. Did you click too fast again or are you using more than one relay?");
 }
 waitFor = llListReplaceList(waitFor, [FALSE], index, index);
 if (!areWeStillWaitingForMessages())
 {
 llSay(0, "PASSED: Got all expected messages.");
 llSetTimerEvent(0);
 }
}
// checks whether we are still waiting for replies
integer areWeStillWaitingForMessages()
{
 integer i;
 integer count = llGetListLength(waitFor);
 for (i = 0; i < count; i++)
 {
 if (llList2Integer(waitFor, i))
 {
 return TRUE;
 }
 }
 return FALSE;
}
// reports which message are still missing
reportTimeout()
{
 integer i;
 integer count = llGetListLength(waitFor);
 string missing = "FAIL: We did not get all expected responses to !version, !implversion and @version in time. Missing: ";
 for (i = 0; i < count; i++)
 {
 if (llList2Integer(waitFor, i))
 {
 missing += llList2String(RESPONSE_NAMES, i) + ", ";
 }
 } 
 llSay(0, missing);
 llSetTimerEvent(0);
}
default
{
 state_entry()
 {
 llSetText(llGetObjectName(), <1, 1, 1>, 1);
 llListen(CHANNEL_RELAY, "", "", "");
 llListen(CHANNEL_VIEWER, "", "", "");
 }
 on_rez(integer ignored)
 {
 llSay(0, "Make sure that you are only wearing one relay and touch me.");
 }
 listen(integer channel, string name, key id, string message)
 {
 if ((llGetOwnerKey(id) == id) && (channel == CHANNEL_VIEWER))
 {
 handleRLVResponse(message);
 }
 if ((llGetOwnerKey(id) == llGetOwner()) && (channel == CHANNEL_RELAY))
 {
 handleRelayResponse(message);
 }
 llOwnerSay(name + ": " + message);
 }
 
 touch_start(integer i)
 {
 if (llDetectedKey(0) != llGetOwner())
 {
 llSay(0, "Hey, " + llDetectedName(0) + " don't mess with me!");
 return;
 }
 llSay(CHANNEL_RELAY, "relaytest," + (string) llGetOwner() + ",!version|!implversion|@version=" + (string) CHANNEL_VIEWER);
 waitFor = [TRUE, TRUE, TRUE, TRUE];
 llSetTimerEvent(10);
 }
 timer()
 {
 reportTimeout();
 }
}