LSL Language Test 2
<lsl> integer gTestsPassed = 0; integer gTestsFailed = 0;
key gNullKey = NULL_KEY; key gStringInAKey = "foo";
integer gVisitedStateTest = FALSE;
testPassed(string description, string actual, string expected) {
++gTestsPassed; //llSay(0, description);
}
testFailed(string description, string actual, string expected) {
++gTestsFailed; llSay(0, "FAILED!: " + description + " (" + actual + " expected " + expected + ")");
}
ensureTrue(string description, integer actual) {
if(actual) { testPassed(description, (string) actual, (string) TRUE); } else { testFailed(description, (string) actual, (string) TRUE); }
}
ensureFalse(string description, integer actual) {
if(actual) { testFailed(description, (string) actual, (string) FALSE); } else { testPassed(description, (string) actual, (string) FALSE); }
}
ensureIntegerEqual(string description, integer actual, integer expected) {
if(actual == expected) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
integer floatEqual(float actual, float expected) {
float error = llFabs(expected - actual); float epsilon = 0.001; if(error > epsilon) { llSay(0,"Float equality delta " + (string)error); return FALSE; } return TRUE;
}
ensureFloatEqual(string description, float actual, float expected) {
if(floatEqual(actual, expected)) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
ensureFloatExactEqual(string description, float actual, float expected) {
if(actual == expected) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
ensureStringEqual(string description, string actual, string expected) {
if(actual == expected) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
ensureKeyEqual(string description, key actual, key expected) {
if(actual == expected) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
ensureVectorEqual(string description, vector actual, vector expected) {
if(floatEqual(actual.x, expected.x) && floatEqual(actual.y, expected.y) && floatEqual(actual.z, expected.z)) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
ensureRotationEqual(string description, rotation actual, rotation expected) {
if(floatEqual(actual.x, expected.x) && floatEqual(actual.y, expected.y) && floatEqual(actual.z, expected.z) && floatEqual(actual.s, expected.s)) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
ensureListEqual(string description, list actual, list expected) {
if(actual == expected) { testPassed(description, (string) actual, (string) expected); } else { testFailed(description, (string) actual, (string) expected); }
}
vector gVector;
float testReturnFloat() {
return 1.0;
}
testArgumentAccessor(vector v) {
v = <0,0,0>; v.x = testReturnFloat(); v.y = testReturnFloat(); v.z = testReturnFloat(); ensureVectorEqual("testArgumentAccessor", v, <1,1,1>);
}
testLocalAccessor() {
vector v = <0,0,0>; v.x = testReturnFloat(); v.y = testReturnFloat(); v.z = testReturnFloat(); ensureVectorEqual("testLocalAccessor", v, <1,1,1>);
}
testGlobalAccessor() {
gVector = <0,0,0>; gVector.x = testReturnFloat(); gVector.y = testReturnFloat(); gVector.z = testReturnFloat(); ensureVectorEqual("testGlobalAccessor", gVector, <1,1,1>);
}
tests() {
// Ensure that multiple states containing the same handler work (SVC-1372 Regression) ensureTrue("gVisitedStateTest ", gVisitedStateTest); ensureFloatExactEqual("1.4e-45 == (float)\"1.4e-45\"", 1.4e-45, (float)"1.4e-45"); // Managed pointer save/restore tests. testArgumentAccessor(<0,0,0>); testLocalAccessor(); testGlobalAccessor(); // Multiple list element saving (SVC-1712 Regression) ensureStringEqual("(string)[1, testReturnFloat(), testReturnFloat()] == \"11.01.0\"", (string)[1, testReturnFloat(), testReturnFloat()], "11.0000001.000000"); // Key equality (SVC-1720 Regression) key k = "foo"; key k2 = "foo"; ensureKeyEqual("k = \"foo\";k2 = \"foo\";k == k2", k, k2); // List comparison. Not actual comparison, just length. ensureIntegerEqual("[] == []", [] == [], 1); ensureIntegerEqual("[1] == [2]", [1] == [2], 1); ensureIntegerEqual("[1,2] == [1,2]", [1,2] == [1,2], 1); ensureIntegerEqual("[1,2] == [2]", [1,2] == [2], 0); ensureIntegerEqual("[1] == [2,3]", [1] == [2,3], 0); ensureIntegerEqual("[] != []", [] != [], 0); ensureIntegerEqual("[1] != [2]", [1] != [2], 0); ensureIntegerEqual("[1,2] != [1,2]", [1,2] != [1,2], 0); ensureIntegerEqual("[1,2] != [2]", [1,2] != [2], 1); ensureIntegerEqual("[1] != [2,3]", [1] != [2,3], -1); // Parsing numbers with junk after ensureFloatEqual("(float)\"5.0a\" == 5.0", (float) "5a", 5.0); ensureFloatEqual("(integer)\"12foo\" == 12", (integer) "12foo", 12); // List value semantics across addition (SVC-1448 Regression) list l; l = [42]; l + 1; ensureListEqual("list l = [42]; l + 1; l == [42]", l, [42]); l = [42]; l + 1.5; ensureListEqual("list l = [42]; l + 1.5; l == [42]", l, [42]); l = [42]; l + NULL_KEY; ensureListEqual("list l = [42]; l + NULL_KEY; l == [42]", l, [42]); l = [42]; l + <1,2,3>; ensureListEqual("list l = [42]; l + <1,2,3>; l == [42]", l, [42]); l = [42]; l + <1,2,3,4>; ensureListEqual("list l = [42]; l + <1,2,3>; l == [42]", l, [42]); // Conditional test of key (SVC-1776/SVC-1811 Regression) if(k) { testFailed("if(k)", "TRUE", "FALSE"); } else { testPassed("if(k)", "FALSE", "FALSE"); } // String/Key equality (SVC-1770 Regression) ensureIntegerEqual("k == \"foo\"",k == "foo", TRUE); // String/Key equality (SVC-1772 Regression) ensureIntegerEqual("gStringInAKey == \"foo\"", gStringInAKey == "foo", TRUE); ensureIntegerEqual("gNullKey == NULL_KEY", gNullKey == NULL_KEY, TRUE); // Key to string cast on assignment (SVC-1707 Regression) k = NULL_KEY; string s; s = k; ensureStringEqual("k = NULL_KEY; string s; s = k;", s, NULL_KEY); // Loop semantics for vectors vector v = <1,1,1>; while (v) { v = ZERO_VECTOR; } ensureVectorEqual( "while (v) { v = ZERO_VECTOR; }", v, ZERO_VECTOR); v = <2,2,2>; do { v = ZERO_VECTOR; } while (v); ensureVectorEqual( "v = <2,2,2>; do { v = ZERO_VECTOR } while (v);", v, ZERO_VECTOR); for (v = <3,3,3>;v;v=ZERO_VECTOR) {} ensureVectorEqual( "for (v = <3,3,3>;v;v=ZERO_VECTOR) {}", v, ZERO_VECTOR); // Loops with keys k = "7c42811e-229f-4500-b6d7-2c37324ff816"; while (k) { k = NULL_KEY; } ensureKeyEqual( "while (k) { k = NULL_KEY; }", k, NULL_KEY); k = "7c42811e-229f-4500-b6d7-2c37324ff816"; do { k = NULL_KEY; } while (k); ensureKeyEqual( "k = \"7c42811e-229f-4500-b6d7-2c37324ff816\"; do { k = NULL_KEY } while (k);", k, NULL_KEY); for (k = "7c42811e-229f-4500-b6d7-2c37324ff816"; k; k=NULL_KEY) {} ensureKeyEqual( "for (k = \"7c42811e-229f-4500-b6d7-2c37324ff816\";k;k=NULL_KEY) {}", k, NULL_KEY); // Loops with rotations rotation q = <1,1,1,1>; while (q) { q = ZERO_ROTATION; } ensureRotationEqual( "while (q) { q = ZERO_ROTATION; }", q, ZERO_ROTATION); q = <2,2,2,2>; do { q = ZERO_ROTATION; } while (q); ensureRotationEqual( "q = <2,2,2>; do { v = ZERO_ROTATION } while (q);", q, ZERO_ROTATION); for (q = <3,3,3,3>; q; q=ZERO_ROTATION) {} ensureRotationEqual( "for (q = <3,3,3,3>;q;q=ZERO_ROTATION) {}", q, ZERO_ROTATION); // Loops with lists l = [1]; while (l) { l = []; } ensureListEqual( "while (l) { l = []; }", l, []); // Fails on LSL, SVC-689 l = [2]; do { l = []; } while (l); ensureListEqual( "l = [2]; do { v = [] } while (l);", l, []); for (l = [3]; l; l=[]) {} ensureListEqual( "for (l = [3];l;l=[]) {}", l, []); // Fails on LSL, SVC-689 // Loop for strings s = "1!"; while (s) { s = ""; } ensureStringEqual( "while (s) { s = \"\"; }", s, ""); s = "2!"; do { s = ""; } while (s); ensureStringEqual( "s = \"2!\"; do { s = \"\" } while (s);", s, ""); for (s = "3!";s;s="") {} ensureStringEqual( "for (s = \"3!\";s;s=\"\") {}", s, ""); // Loop for integers integer i = 1; while (i) { i = 0; } ensureIntegerEqual( "while (i) { i = 0; }", i, 0); i = 2; do { i = 0; } while (i); ensureIntegerEqual( "i = 2; do { i = 0 } while (i);", i, 0); for (i = 3;i;i=0) {} ensureIntegerEqual( "for (i = 3;i;i=0) {}", i, 0); // Loop for floats float f = 1; while (f) { f = 0; } ensureFloatEqual( "while (f) { f = 0; }", f, 0); f = 2; do { f = 0; } while (f); ensureFloatEqual( "f = 2; do { f = 0 } while (f);", f, 0); for (f = 3;f;f=0) {} ensureFloatEqual( "for (f = 3;f;f=0) {}", f, 0);
}
runTests() {
llResetTime(); tests(); llSay(0, "Ran " + (string)(gTestsPassed + gTestsFailed) + " tests in " + (string) llGetTime() + " seconds with " + (string)gTestsFailed + " failures");
// Reset globals. gVisitedStateTest = FALSE; gTestsPassed = 0; gTestsFailed = 0;
}
default {
state_entry() { state StateTest; } touch_start(integer total_number) { state StateTest; }
}
state StateTest {
state_entry() { ensureFalse("gVisitedStateTest", gVisitedStateTest); gVisitedStateTest = TRUE; runTests(); } touch_start(integer total_number) { state default; }
} </lsl>