Difference between revisions of "LSL Language Test"

From Second Life Wiki
Jump to navigation Jump to search
Line 9: Line 9:
<lsl>integer gTestsPassed = 0;
<lsl>integer gTestsPassed = 0;
integer gTestsFailed = 0;
integer gTestsFailed = 0;
 
testPassed(string description, string actual, string expected)
testPassed(string description, string actual, string expected)
{
{
Line 15: Line 15:
     //llSay(0, description);
     //llSay(0, description);
}
}
 
testFailed(string description, string actual, string expected)
testFailed(string description, string actual, string expected)
{
{
Line 21: Line 21:
     llSay(0, "FAILED!: " + description + " (" + actual + " expected " + expected + ")");
     llSay(0, "FAILED!: " + description + " (" + actual + " expected " + expected + ")");
}
}
 
ensureTrue(string description, integer actual)
ensureTrue(string description, integer actual)
{
{
Line 33: Line 33:
     }
     }
}
}
 
ensureFalse(string description, integer actual)
ensureFalse(string description, integer actual)
{
{
Line 45: Line 45:
     }
     }
}
}
 
ensureIntegerEqual(string description, integer actual, integer expected)
ensureIntegerEqual(string description, integer actual, integer expected)
{
{
Line 57: Line 57:
     }
     }
}
}
 
integer floatEqual(float actual, float expected)
integer floatEqual(float actual, float expected)
{
{
Line 69: Line 69:
     return TRUE;
     return TRUE;
}
}
 
ensureFloatEqual(string description, float actual, float expected)
ensureFloatEqual(string description, float actual, float expected)
{
{
Line 81: Line 81:
     }
     }
}
}
 
ensureStringEqual(string description, string actual, string expected)
ensureStringEqual(string description, string actual, string expected)
{
{
Line 93: Line 93:
     }
     }
}
}
 
ensureVectorEqual(string description, vector actual, vector expected)
ensureVectorEqual(string description, vector actual, vector expected)
{
{
Line 107: Line 107:
     }
     }
}
}
 
ensureRotationEqual(string description, rotation actual, rotation expected)
ensureRotationEqual(string description, rotation actual, rotation expected)
{
{
Line 122: Line 122:
     }
     }
}
}
 
ensureListEqual(string description, list actual, list expected)
ensureListEqual(string description, list actual, list expected)
{
{
Line 134: Line 134:
     }
     }
}
}
 
integer gInteger = 5;
integer gInteger = 5;
float gFloat = 1.5;
float gFloat = 1.5;
Line 141: Line 141:
rotation gRot = <1, 2, 3, 4>;
rotation gRot = <1, 2, 3, 4>;
list gList = [1, 2, 3];
list gList = [1, 2, 3];
 
integer testReturn()
integer testReturn()
{
{
     return 1;
     return 1;
}
}
 
float testReturnFloat()
float testReturnFloat()
{
{
     return 1;
     return 1;
}
}
 
string testReturnString()
string testReturnString()
{
{
     return "Test string";
     return "Test string";
}
}
 
list testReturnList()
list testReturnList()
{
{
     return [1,2,3];
     return [1,2,3];
}
}
 
vector testReturnVector()
vector testReturnVector()
{
{
     return <1,2,3>;
     return <1,2,3>;
}
}
 
rotation testReturnRotation()
rotation testReturnRotation()
{
{
     return <1,2,3,4>;
     return <1,2,3,4>;
}
}
 
vector testReturnVectorNested()
vector testReturnVectorNested()
{
{
     return testReturnVector();
     return testReturnVector();
}
}
 
vector testReturnVectorWithLibraryCall()
vector testReturnVectorWithLibraryCall()
{
{
Line 182: Line 182:
     return <1,2,3>;
     return <1,2,3>;
}
}
 
rotation testReturnRotationWithLibraryCall()
rotation testReturnRotationWithLibraryCall()
{
{
Line 188: Line 188:
     return <1,2,3,4>;
     return <1,2,3,4>;
}
}
 
integer testParameters(integer param)
integer testParameters(integer param)
{
{
Line 194: Line 194:
     return param;
     return param;
}
}
 
integer testRecursion(integer param)
integer testRecursion(integer param)
{
{
Line 206: Line 206:
     }
     }
}
}
 
string testExpressionLists(list l)
string testExpressionLists(list l)
{
{
     return "foo" + (string)l;
     return "foo" + (string)l;
}
}
 
tests()
tests()
{
{
Line 217: Line 217:
     ensureIntegerEqual("TRUE", TRUE, TRUE);
     ensureIntegerEqual("TRUE", TRUE, TRUE);
     ensureIntegerEqual("FALSE", FALSE, FALSE);
     ensureIntegerEqual("FALSE", FALSE, FALSE);
 
     if(0.0)
     if(0.0)
     {
     {
Line 258: Line 258:
         testPassed("if(ZERO_ROTATION)", "TRUE", "TRUE");
         testPassed("if(ZERO_ROTATION)", "TRUE", "TRUE");
     }
     }
 
     if(NULL_KEY)
     if(NULL_KEY)
     {
     {
Line 275: Line 275:
         testPassed("if((key)NULL_KEY)", "TRUE", "TRUE");
         testPassed("if((key)NULL_KEY)", "TRUE", "TRUE");
     }
     }
   
     if("")
     if("")
     {
     {
Line 284: Line 284:
         testPassed("if(\"\")", "TRUE", "TRUE");
         testPassed("if(\"\")", "TRUE", "TRUE");
     }
     }
 
     if([])
     if([])
     {
     {
Line 293: Line 293:
         testPassed("if([])", "TRUE", "TRUE");
         testPassed("if([])", "TRUE", "TRUE");
     }
     }
   
     // equality
     // equality
     ensureIntegerEqual("(TRUE == TRUE)", (TRUE == TRUE), TRUE);
     ensureIntegerEqual("(TRUE == TRUE)", (TRUE == TRUE), TRUE);
Line 299: Line 299:
     ensureIntegerEqual("(FALSE == TRUE)", (FALSE == TRUE), FALSE);
     ensureIntegerEqual("(FALSE == TRUE)", (FALSE == TRUE), FALSE);
     ensureIntegerEqual("(FALSE == FALSE)", (FALSE == FALSE), TRUE);
     ensureIntegerEqual("(FALSE == FALSE)", (FALSE == FALSE), TRUE);
   
     // inequality
     // inequality
     ensureIntegerEqual("(TRUE != TRUE)", (TRUE != TRUE), FALSE);
     ensureIntegerEqual("(TRUE != TRUE)", (TRUE != TRUE), FALSE);
Line 305: Line 305:
     ensureIntegerEqual("(FALSE != TRUE)", (FALSE != TRUE), TRUE);
     ensureIntegerEqual("(FALSE != TRUE)", (FALSE != TRUE), TRUE);
     ensureIntegerEqual("(FALSE != FALSE)", (FALSE != FALSE), FALSE);
     ensureIntegerEqual("(FALSE != FALSE)", (FALSE != FALSE), FALSE);
   
     // and
     // and
     ensureIntegerEqual("(TRUE && TRUE)", (TRUE && TRUE), TRUE);
     ensureIntegerEqual("(TRUE && TRUE)", (TRUE && TRUE), TRUE);
Line 311: Line 311:
     ensureIntegerEqual("(FALSE && TRUE)", (FALSE && TRUE), FALSE);
     ensureIntegerEqual("(FALSE && TRUE)", (FALSE && TRUE), FALSE);
     ensureIntegerEqual("(FALSE && FALSE)", (FALSE && FALSE), FALSE);
     ensureIntegerEqual("(FALSE && FALSE)", (FALSE && FALSE), FALSE);
 
     // and
     // and
     ensureIntegerEqual("(1 && 2)", (1 && 2), TRUE);
     ensureIntegerEqual("(1 && 2)", (1 && 2), TRUE);
Line 317: Line 317:
     ensureIntegerEqual("(0 && 2)", (0 && 2), FALSE);
     ensureIntegerEqual("(0 && 2)", (0 && 2), FALSE);
     ensureIntegerEqual("(0 && 0)", (0 && 0), FALSE);
     ensureIntegerEqual("(0 && 0)", (0 && 0), FALSE);
 
       
     // or
     // or
     ensureIntegerEqual("(TRUE || TRUE)", (TRUE || TRUE), TRUE);
     ensureIntegerEqual("(TRUE || TRUE)", (TRUE || TRUE), TRUE);
Line 324: Line 324:
     ensureIntegerEqual("(FALSE || TRUE)", (FALSE || TRUE), TRUE);
     ensureIntegerEqual("(FALSE || TRUE)", (FALSE || TRUE), TRUE);
     ensureIntegerEqual("(FALSE || FALSE)", (FALSE || FALSE), FALSE);
     ensureIntegerEqual("(FALSE || FALSE)", (FALSE || FALSE), FALSE);
   
     // or
     // or
     ensureIntegerEqual("(1 || 2)", (1 || 2), TRUE);
     ensureIntegerEqual("(1 || 2)", (1 || 2), TRUE);
Line 330: Line 330:
     ensureIntegerEqual("(0 || 2)", (0 || 2), TRUE);
     ensureIntegerEqual("(0 || 2)", (0 || 2), TRUE);
     ensureIntegerEqual("(0 || 0)", (0 || 0), FALSE);
     ensureIntegerEqual("(0 || 0)", (0 || 0), FALSE);
       
     // not
     // not
     ensureIntegerEqual("(! TRUE)", (! TRUE), FALSE);
     ensureIntegerEqual("(! TRUE)", (! TRUE), FALSE);
     ensureIntegerEqual("(! FALSE)", (! FALSE), TRUE);
     ensureIntegerEqual("(! FALSE)", (! FALSE), TRUE);
   
     // not  
     // not  
     ensureIntegerEqual("(! 2)", (! 2), FALSE);
     ensureIntegerEqual("(! 2)", (! 2), FALSE);
     ensureIntegerEqual("(! 0)", (! 0), TRUE);
     ensureIntegerEqual("(! 0)", (! 0), TRUE);
   
   
     // greater than
     // greater than
     ensureIntegerEqual("(1 > 0)", (1 > 0), TRUE);
     ensureIntegerEqual("(1 > 0)", (1 > 0), TRUE);
     ensureIntegerEqual("(0 > 1)", (0 > 1), FALSE);
     ensureIntegerEqual("(0 > 1)", (0 > 1), FALSE);
     ensureIntegerEqual("(1 > 1)", (1 > 1), FALSE);
     ensureIntegerEqual("(1 > 1)", (1 > 1), FALSE);
   
     // less than
     // less than
     ensureIntegerEqual("(0 < 1)", (0 < 1), TRUE);
     ensureIntegerEqual("(0 < 1)", (0 < 1), TRUE);
     ensureIntegerEqual("(1 < 0)", (1 < 0), FALSE);
     ensureIntegerEqual("(1 < 0)", (1 < 0), FALSE);
     ensureIntegerEqual("(1 < 1)", (1 < 1), FALSE);
     ensureIntegerEqual("(1 < 1)", (1 < 1), FALSE);
   
     // greater than or equal
     // greater than or equal
     ensureIntegerEqual("(1 >= 0)", (1 >= 0), TRUE);
     ensureIntegerEqual("(1 >= 0)", (1 >= 0), TRUE);
     ensureIntegerEqual("(0 >= 1)", (0 >= 1), FALSE);
     ensureIntegerEqual("(0 >= 1)", (0 >= 1), FALSE);
     ensureIntegerEqual("(1 >= 1)", (1 >= 1), TRUE);
     ensureIntegerEqual("(1 >= 1)", (1 >= 1), TRUE);
   
     // tess than or equal
     // tess than or equal
     ensureIntegerEqual("(0 <= 1)", (0 <= 1), TRUE);
     ensureIntegerEqual("(0 <= 1)", (0 <= 1), TRUE);
     ensureIntegerEqual("(1 <= 0)", (1 <= 0), FALSE);
     ensureIntegerEqual("(1 <= 0)", (1 <= 0), FALSE);
     ensureIntegerEqual("(1 <= 1)", (1 <= 1), TRUE);
     ensureIntegerEqual("(1 <= 1)", (1 <= 1), TRUE);
   
     // bitwise and
     // bitwise and
     ensureIntegerEqual("(10 & 25)", (10 & 25), 8);
     ensureIntegerEqual("(10 & 25)", (10 & 25), 8);
   
     // bitwise or
     // bitwise or
     ensureIntegerEqual("(10 | 25)", (10 | 25), 27);
     ensureIntegerEqual("(10 | 25)", (10 | 25), 27);
   
     // bitwise not
     // bitwise not
     ensureIntegerEqual("~10", ~10, -11);
     ensureIntegerEqual("~10", ~10, -11);
   
     // xor
     // xor
     ensureIntegerEqual("(10 ^ 25)", (10 ^ 25), 19);
     ensureIntegerEqual("(10 ^ 25)", (10 ^ 25), 19);
   
     // right shift
     // right shift
     ensureIntegerEqual("(523 >> 2)", (523 >> 2), 130);
     ensureIntegerEqual("(523 >> 2)", (523 >> 2), 130);
   
     // left shift
     // left shift
     ensureIntegerEqual("(523 << 2)", (523 << 2), 2092);
     ensureIntegerEqual("(523 << 2)", (523 << 2), 2092);
   
     // addition
     // addition
     ensureIntegerEqual("(1 + 1)", (1 + 1), 2);
     ensureIntegerEqual("(1 + 1)", (1 + 1), 2);
Line 391: Line 391:
     ensureListEqual("([] + <1,2,3>)", ([] + <1,2,3>), [<1,2,3>]);
     ensureListEqual("([] + <1,2,3>)", ([] + <1,2,3>), [<1,2,3>]);
     ensureListEqual("([] + <1,2,3,4>)", ([] + <1,2,3,4>), [<1,2,3,4>]);
     ensureListEqual("([] + <1,2,3,4>)", ([] + <1,2,3,4>), [<1,2,3,4>]);
   
     ensureListEqual("(1 + [2])", (1 + [2]), [1,2]);
     ensureListEqual("(1 + [2])", (1 + [2]), [1,2]);
     ensureListEqual("(1.0 + [2])", (1.0 + [2]), [1.0,2]);
     ensureListEqual("(1.0 + [2])", (1.0 + [2]), [1.0,2]);
Line 397: Line 397:
     ensureListEqual("(<1.0,1.0,1.0,1.0> + [2])", (<1.0,1.0,1.0,1.0> + [2]), [<1.0,1.0,1.0,1.0>,2]);
     ensureListEqual("(<1.0,1.0,1.0,1.0> + [2])", (<1.0,1.0,1.0,1.0> + [2]), [<1.0,1.0,1.0,1.0>,2]);
     ensureListEqual("(<1.0,1.0,1.0> + [2])", (<1.0,1.0,1.0> + [2]), [<1.0,1.0,1.0>,2]);
     ensureListEqual("(<1.0,1.0,1.0> + [2])", (<1.0,1.0,1.0> + [2]), [<1.0,1.0,1.0>,2]);
 
 
     // subtraction
     // subtraction
     ensureIntegerEqual("(1 - 1)", (1 - 1), 0);
     ensureIntegerEqual("(1 - 1)", (1 - 1), 0);
Line 406: Line 406:
     ensureVectorEqual("(<1.5, 2.5, 3.5> - <4.5, 5.5, 6.5>)", (<1.5, 2.5, 3.5> - <4.5, 5.5, 6.5>), <-3.0, -3.0, -3.0>);
     ensureVectorEqual("(<1.5, 2.5, 3.5> - <4.5, 5.5, 6.5>)", (<1.5, 2.5, 3.5> - <4.5, 5.5, 6.5>), <-3.0, -3.0, -3.0>);
     ensureRotationEqual("(<1.5, 2.5, 3.5, 4.5> - <4.5, 5.5, 6.5, 7.5>)", (<1.5, 2.5, 3.5, 4.5> - <4.5, 5.5, 6.5, 7.5>), <-3.0, -3.0, -3.0, -3.0>);
     ensureRotationEqual("(<1.5, 2.5, 3.5, 4.5> - <4.5, 5.5, 6.5, 7.5>)", (<1.5, 2.5, 3.5, 4.5> - <4.5, 5.5, 6.5, 7.5>), <-3.0, -3.0, -3.0, -3.0>);
 
     // multiplication
     // multiplication
     ensureIntegerEqual("(2 * 3)", (2 * 3), 6);
     ensureIntegerEqual("(2 * 3)", (2 * 3), 6);
Line 419: Line 419:
     ensureVectorEqual("<-1,0,0> * <0, 0, 0.707, 0.707>", <-1,0,0> * <0, 0, 0.707, 0.707>, <0,-1, 0>);
     ensureVectorEqual("<-1,0,0> * <0, 0, 0.707, 0.707>", <-1,0,0> * <0, 0, 0.707, 0.707>, <0,-1, 0>);
     ensureRotationEqual("(<1.0, 2.0, 3.0, 4.0> * <5.0, 6.0, 7.0, 8.0>)", (<1.0, 2.0, 3.0, 4.0> * <5.0, 6.0, 7.0, 8.0>), <32.0, 32.0, 56.0, -6.0>);
     ensureRotationEqual("(<1.0, 2.0, 3.0, 4.0> * <5.0, 6.0, 7.0, 8.0>)", (<1.0, 2.0, 3.0, 4.0> * <5.0, 6.0, 7.0, 8.0>), <32.0, 32.0, 56.0, -6.0>);
   
 
     // division
     // division
     ensureIntegerEqual("(2 / 2)", (2 / 2), 1);
     ensureIntegerEqual("(2 / 2)", (2 / 2), 1);
Line 430: Line 430:
     ensureVectorEqual("<-1,0,0> / <0, 0, 0.707, 0.707>", <-1,0,0> / <0, 0, 0.707, 0.707>, <0,1, 0>);
     ensureVectorEqual("<-1,0,0> / <0, 0, 0.707, 0.707>", <-1,0,0> / <0, 0, 0.707, 0.707>, <0,1, 0>);
     ensureRotationEqual("(<1.0, 2.0, 3.0, 4.0> / <5.0, 6.0, 7.0, 8.0>)", (<1.0, 2.0, 3.0, 4.0> / <5.0, 6.0, 7.0, 8.0>), <-16.0, 0.0, -8.0, 70.0>);
     ensureRotationEqual("(<1.0, 2.0, 3.0, 4.0> / <5.0, 6.0, 7.0, 8.0>)", (<1.0, 2.0, 3.0, 4.0> / <5.0, 6.0, 7.0, 8.0>), <-16.0, 0.0, -8.0, 70.0>);
 
     // modulo
     // modulo
     ensureIntegerEqual("(3 % 1)", (3 % 1), 0);
     ensureIntegerEqual("(3 % 1)", (3 % 1), 0);
     ensureVectorEqual("(<1.0, 2.0, 3.0> % <4.0, 5.0, 6.0>)", (<1.0, 2.0, 3.0> % <4.0, 5.0, 6.0>), <-3.0, 6.0, -3.0>);
     ensureVectorEqual("(<1.0, 2.0, 3.0> % <4.0, 5.0, 6.0>)", (<1.0, 2.0, 3.0> % <4.0, 5.0, 6.0>), <-3.0, 6.0, -3.0>);
   
     // assignment
     // assignment
     integer i = 1;
     integer i = 1;
     ensureIntegerEqual("i = 1;", i, 1);
     ensureIntegerEqual("i = 1;", i, 1);
   
     // addition assignment
     // addition assignment
     i = 1;
     i = 1;
     i += 1;
     i += 1;
     ensureIntegerEqual("i = 1; i += 1;", i, 2);
     ensureIntegerEqual("i = 1; i += 1;", i, 2);
   
     // subtraction assignment
     // subtraction assignment
     i = 1;
     i = 1;
     i -= 1;
     i -= 1;
     ensureIntegerEqual("i = 1; i -= 1;", i, 0);
     ensureIntegerEqual("i = 1; i -= 1;", i, 0);
   
     // multiplication assignment integer *= integer
     // multiplication assignment integer *= integer
     i = 2;
     i = 2;
     i *= 2;
     i *= 2;
     ensureIntegerEqual("i = 2; i *= 2;", i, 4);
     ensureIntegerEqual("i = 2; i *= 2;", i, 4);
   
     // multiplication assignment integer *= float
     // multiplication assignment integer *= float
     i = 1;
     i = 1;
     i *= 0.5;
     i *= 0.5;
     ensureIntegerEqual("i = 1; i *= 0.5;", i, 0);
     ensureIntegerEqual("i = 1; i *= 0.5;", i, 0);
       
     // division assignment
     // division assignment
     i = 2;
     i = 2;
Line 464: Line 464:
     ensureIntegerEqual("i = 2; i /= 2;", i, 1);
     ensureIntegerEqual("i = 2; i /= 2;", i, 1);
      
      
    // check overflow behaviour
    i = 0x80000000 / -1;
    ensureIntegerEqual("i = 0x80000000 / -1;", i, -2147483648);
     // modulo assignment
     // modulo assignment
     i = 3;
     i = 3;
     i %= 1;
     i %= 1;
     ensureIntegerEqual("i = 3; i %= 1;", i, 0);
     ensureIntegerEqual("i = 3; i %= 1;", i, 0);
      
     // check overflow behaviour
    i = 0x80000000 % -1;
    ensureIntegerEqual("i = 0x80000000 & -1;", i, 0);
     // post increment.
     // post increment.
     i = 1;
     i = 1;
     ensureIntegerEqual("i = 1; (i == 2) && (i++ == 1)", (i == 2) && (i++ == 1), TRUE);
     ensureIntegerEqual("i = 1; (i == 2) && (i++ == 1)", (i == 2) && (i++ == 1), TRUE);
       
     // pre increment.
     // pre increment.
     i = 1;
     i = 1;
     ensureIntegerEqual("i = 1; (i == 2) && (++i == 2)", (i == 2) && (++i == 2), TRUE);
     ensureIntegerEqual("i = 1; (i == 2) && (++i == 2)", (i == 2) && (++i == 2), TRUE);
       
     // post decrement.
     // post decrement.
     i = 2;
     i = 2;
     ensureIntegerEqual("i = 2; (i == 1) && (i-- == 2)", (i == 1) && (i-- == 2), TRUE);
     ensureIntegerEqual("i = 2; (i == 1) && (i-- == 2)", (i == 1) && (i-- == 2), TRUE);
       
     // pre decrement.
     // pre decrement.
     i = 2;
     i = 2;
Line 486: Line 494:
     i = 2; --i;
     i = 2; --i;
     ensureIntegerEqual("i = 2; --i", i, 1);
     ensureIntegerEqual("i = 2; --i", i, 1);
   
     // casting
     // casting
     ensureFloatEqual("((float)2)", ((float)2), 2.0);
     ensureFloatEqual("((float)2)", ((float)2), 2.0);
Line 500: Line 508:
     ensureStringEqual("((string) <1,2,3,4>)", ((string) <1,2,3,4>), "<1.00000, 2.00000, 3.00000, 4.00000>");
     ensureStringEqual("((string) <1,2,3,4>)", ((string) <1,2,3,4>), "<1.00000, 2.00000, 3.00000, 4.00000>");
     ensureStringEqual("((string) [1,2.5,<1,2,3>])", ((string) [1,2.5,<1,2,3>]), "12.500000<1.000000, 2.000000, 3.000000>");
     ensureStringEqual("((string) [1,2.5,<1,2,3>])", ((string) [1,2.5,<1,2,3>]), "12.500000<1.000000, 2.000000, 3.000000>");
   
     // while
     // while
     i = 0;
     i = 0;
     while(i < 10) ++i;
     while(i < 10) ++i;
     ensureIntegerEqual("i = 0; while(i < 10) ++i", i, 10);
     ensureIntegerEqual("i = 0; while(i < 10) ++i", i, 10);
   
     // do while
     // do while
     i = 0;
     i = 0;
     do {++i;} while(i < 10);
     do {++i;} while(i < 10);
     ensureIntegerEqual("i = 0; do {++i;} while(i < 10);", i, 10);
     ensureIntegerEqual("i = 0; do {++i;} while(i < 10);", i, 10);
   
     // for
     // for
     for(i = 0; i < 10; ++i);
     for(i = 0; i < 10; ++i);
     ensureIntegerEqual("for(i = 0; i < 10; ++i);", i, 10);
     ensureIntegerEqual("for(i = 0; i < 10; ++i);", i, 10);
   
     // jump
     // jump
     i = 1;
     i = 1;
Line 522: Line 530:
     @SkipAssign;
     @SkipAssign;
     ensureIntegerEqual("i = 1; jump SkipAssign; i = 2; @SkipAssign;", i, 1);
     ensureIntegerEqual("i = 1; jump SkipAssign; i = 2; @SkipAssign;", i, 1);
   
     // return
     // return
     ensureIntegerEqual("testReturn()", testReturn(), 1);
     ensureIntegerEqual("testReturn()", testReturn(), 1);
Line 532: Line 540:
     ensureVectorEqual("testReturnVectorWithLibraryCall()", testReturnVectorWithLibraryCall(), <1,2,3>);
     ensureVectorEqual("testReturnVectorWithLibraryCall()", testReturnVectorWithLibraryCall(), <1,2,3>);
     ensureRotationEqual("testReturnRotationWithLibraryCall()", testReturnRotationWithLibraryCall(), <1,2,3,4>);
     ensureRotationEqual("testReturnRotationWithLibraryCall()", testReturnRotationWithLibraryCall(), <1,2,3,4>);
   
     // parameters
     // parameters
     ensureIntegerEqual("testParameters(1)", testParameters(1), 2);
     ensureIntegerEqual("testParameters(1)", testParameters(1), 2);
   
     // variable parameters
     // variable parameters
     i = 1;
     i = 1;
     ensureIntegerEqual("i = 1; testParameters(i)", testParameters(i), 2);
     ensureIntegerEqual("i = 1; testParameters(i)", testParameters(i), 2);
   
     // recursion
     // recursion
     ensureIntegerEqual("testRecursion(10)", testRecursion(10), 0);
     ensureIntegerEqual("testRecursion(10)", testRecursion(10), 0);
   
     // globals
     // globals
     ensureIntegerEqual("gInteger", gInteger, 5);
     ensureIntegerEqual("gInteger", gInteger, 5);
Line 550: Line 558:
     ensureRotationEqual("gRot", gRot, <1, 2, 3, 4>);
     ensureRotationEqual("gRot", gRot, <1, 2, 3, 4>);
     ensureListEqual("gList", gList, [1, 2, 3]);
     ensureListEqual("gList", gList, [1, 2, 3]);
   
     // global assignment
     // global assignment
     gInteger = 1;
     gInteger = 1;
     ensureIntegerEqual("gInteger = 1", gInteger, 1);
     ensureIntegerEqual("gInteger = 1", gInteger, 1);
   
     gFloat = 0.5;
     gFloat = 0.5;
     ensureFloatEqual("gFloat = 0.5", gFloat, 0.5);
     ensureFloatEqual("gFloat = 0.5", gFloat, 0.5);
   
     gString = "bar";
     gString = "bar";
     ensureStringEqual("gString = \"bar\"", gString, "bar");
     ensureStringEqual("gString = \"bar\"", gString, "bar");
   
     gVector = <3,3,3>;
     gVector = <3,3,3>;
     ensureVectorEqual("gVector = <3,3,3>", gVector, <3,3,3>);
     ensureVectorEqual("gVector = <3,3,3>", gVector, <3,3,3>);
   
     gRot = <3,3,3,3>;
     gRot = <3,3,3,3>;
     ensureRotationEqual("gRot = <3,3,3,3>", gRot, <3,3,3,3>);
     ensureRotationEqual("gRot = <3,3,3,3>", gRot, <3,3,3,3>);
 
     gList = [4,5,6];
     gList = [4,5,6];
     ensureListEqual("gList = [4,5,6]", gList, [4,5,6]);
     ensureListEqual("gList = [4,5,6]", gList, [4,5,6]);
   
     // negation
     // negation
     gVector = <3,3,3>;
     gVector = <3,3,3>;
     ensureVectorEqual("-gVector = <-3,-3,-3>", -gVector, <-3,-3,-3>);
     ensureVectorEqual("-gVector = <-3,-3,-3>", -gVector, <-3,-3,-3>);
   
     gRot = <3,3,3,3>;
     gRot = <3,3,3,3>;
     ensureRotationEqual("-gRot = <-3,-3,-3,-3>", -gRot, <-3,-3,-3,-3>);
     ensureRotationEqual("-gRot = <-3,-3,-3,-3>", -gRot, <-3,-3,-3,-3>);
 
 
     // vector accessor
     // vector accessor
     vector v;
     vector v;
     v.x = 3;
     v.x = 3;
     ensureFloatEqual("v.x", v.x, 3);
     ensureFloatEqual("v.x", v.x, 3);
   
     // rotation accessor
     // rotation accessor
     rotation q;
     rotation q;
     q.s = 5;
     q.s = 5;
     ensureFloatEqual("q.s", q.s, 5);
     ensureFloatEqual("q.s", q.s, 5);
   
     // global vector accessor
     // global vector accessor
     gVector.y = 17.5;
     gVector.y = 17.5;
     ensureFloatEqual("gVector.y = 17.5", gVector.y, 17.5);
     ensureFloatEqual("gVector.y = 17.5", gVector.y, 17.5);
   
     // global rotation accessor
     // global rotation accessor
     gRot.z = 19.5;
     gRot.z = 19.5;
     ensureFloatEqual("gRot.z = 19.5", gRot.z, 19.5);
     ensureFloatEqual("gRot.z = 19.5", gRot.z, 19.5);
   
     // list equality
     // list equality
     list l = (list) 5;
     list l = (list) 5;
Line 602: Line 610:
     ensureListEqual("list l = (list) 5", l, [5]);
     ensureListEqual("list l = (list) 5", l, [5]);
     ensureListEqual("[1.5, 6, <1,2,3>, <1,2,3,4>]", [1.5, 6, <1,2,3>, <1,2,3,4>], [1.5, 6, <1,2,3>, <1,2,3,4>]);
     ensureListEqual("[1.5, 6, <1,2,3>, <1,2,3,4>]", [1.5, 6, <1,2,3>, <1,2,3,4>], [1.5, 6, <1,2,3>, <1,2,3,4>]);
 
     // String escaping
     // String escaping
     ensureIntegerEqual("llStringLength(\"\\\") == 1", llStringLength("\\"), 1);
     ensureIntegerEqual("llStringLength(\"\\\") == 1", llStringLength("\\"), 1);
Line 608: Line 616:
     ensureIntegerEqual("llStringLength(\"\\n\") == 1", llStringLength("\n"), 1);
     ensureIntegerEqual("llStringLength(\"\\n\") == 1", llStringLength("\n"), 1);
     ensureIntegerEqual("llStringLength(\"\\\"\") == 1", llStringLength("\""), 1);
     ensureIntegerEqual("llStringLength(\"\\\"\") == 1", llStringLength("\""), 1);
 
     // Nested expression lists
     // Nested expression lists
     ensureStringEqual("testExpressionLists([testExpressionLists([]), \"bar\"]) == \"foofoobar\"", testExpressionLists([testExpressionLists([]), "bar"]), "foofoobar");
     ensureStringEqual("testExpressionLists([testExpressionLists([]), \"bar\"]) == \"foofoobar\"", testExpressionLists([testExpressionLists([]), "bar"]), "foofoobar");
 
}
}
 
default
default
{
{
Line 621: Line 629:
         tests();
         tests();
         llSay(0, "Ran " + (string)(gTestsPassed + gTestsFailed) + " tests in " + (string) llGetTime() + " seconds with " + (string)gTestsFailed + " failures");
         llSay(0, "Ran " + (string)(gTestsPassed + gTestsFailed) + " tests in " + (string) llGetTime() + " seconds with " + (string)gTestsFailed + " failures");
       
         // reset globals   
         // reset globals   
         gInteger = 5;
         gInteger = 5;
Line 632: Line 640:
         gTestsFailed = 0;
         gTestsFailed = 0;
     }
     }
   
     http_response(key request_id, integer status, list metadata, string body)
     http_response(key request_id, integer status, list metadata, string body)
     {
     {
       
     }
     }
}
}</lsl>
</lsl>

Revision as of 08:50, 5 February 2008


  • Tests all LSL language features
  • To run, rez a prim, add this script, then touch the prim
  • On successful completion, says "Ran N tests in X seconds with 0 failures"
  • For more verbose reporting, uncomment llSay call in testPassed

<lsl>integer gTestsPassed = 0; integer gTestsFailed = 0;

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);
   }

}

ensureStringEqual(string description, string actual, string 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);
   }

}

integer gInteger = 5; float gFloat = 1.5; string gString = "foo"; vector gVector = <1, 2, 3>; rotation gRot = <1, 2, 3, 4>; list gList = [1, 2, 3];

integer testReturn() {

   return 1;

}

float testReturnFloat() {

   return 1;

}

string testReturnString() {

   return "Test string";

}

list testReturnList() {

   return [1,2,3];

}

vector testReturnVector() {

   return <1,2,3>;

}

rotation testReturnRotation() {

   return <1,2,3,4>;

}

vector testReturnVectorNested() {

   return testReturnVector();

}

vector testReturnVectorWithLibraryCall() {

   llSin(0);
   return <1,2,3>;

}

rotation testReturnRotationWithLibraryCall() {

   llSin(0);
   return <1,2,3,4>;

}

integer testParameters(integer param) {

   param = param + 1;
   return param;

}

integer testRecursion(integer param) {

   if(param <= 0)
   {
       return 0;
   }
   else
   {
       return testRecursion(param - 1);
   }

}

string testExpressionLists(list l) {

   return "foo" + (string)l;

}

tests() {

   // truth
   ensureIntegerEqual("TRUE", TRUE, TRUE);
   ensureIntegerEqual("FALSE", FALSE, FALSE);

   if(0.0)
   {
       testFailed("if(0.0)", "TRUE", "FALSE");
   }
   else
   {
       testPassed("if(0.0)", "TRUE", "TRUE");
   }
   if(0.000001)
   {
       testPassed("if(0.000001)", "TRUE", "TRUE");
   }
   else
   {
       testFailed("if(0.000001)", "TRUE", "FALSE");
   }
   if(0.9)
   {
       testPassed("if(0.9)", "TRUE", "TRUE");
   }
   else
   {
       testFailed("if(0.9)", "TRUE", "FALSE");
   }
   if(ZERO_VECTOR)
   {
       testFailed("if(ZERO_VECTOR)", "TRUE", "FALSE");
   }
   else
   {
       testPassed("if(ZERO_VECTOR)", "TRUE", "TRUE");
   }
   if(ZERO_ROTATION)
   {
       testFailed("if(ZERO_ROTATION)", "TRUE", "FALSE");
   }
   else
   {
       testPassed("if(ZERO_ROTATION)", "TRUE", "TRUE");
   }

   if(NULL_KEY)
   {
       testPassed("if(NULL_KEY)", "TRUE", "TRUE");
   }
   else
   {
       testFailed("if(NULL_KEY)", "TRUE", "FALSE");
   }
   if((key)NULL_KEY)
   {
       testFailed("if((key)NULL_KEY)", "TRUE", "FALSE");
   }
   else
   {
       testPassed("if((key)NULL_KEY)", "TRUE", "TRUE");
   }

   if("")
   {
       testFailed("if(\"\")", "TRUE", "FALSE");
   }
   else
   {
       testPassed("if(\"\")", "TRUE", "TRUE");
   }

   if([])
   {
       testFailed("if([])", "TRUE", "FALSE");
   }
   else
   {
       testPassed("if([])", "TRUE", "TRUE");
   }

   // equality
   ensureIntegerEqual("(TRUE == TRUE)", (TRUE == TRUE), TRUE);
   ensureIntegerEqual("(TRUE == FALSE)", (TRUE == FALSE), FALSE);
   ensureIntegerEqual("(FALSE == TRUE)", (FALSE == TRUE), FALSE);
   ensureIntegerEqual("(FALSE == FALSE)", (FALSE == FALSE), TRUE);

   // inequality
   ensureIntegerEqual("(TRUE != TRUE)", (TRUE != TRUE), FALSE);
   ensureIntegerEqual("(TRUE != FALSE)", (TRUE != FALSE), TRUE);
   ensureIntegerEqual("(FALSE != TRUE)", (FALSE != TRUE), TRUE);
   ensureIntegerEqual("(FALSE != FALSE)", (FALSE != FALSE), FALSE);

   // and
   ensureIntegerEqual("(TRUE && TRUE)", (TRUE && TRUE), TRUE);
   ensureIntegerEqual("(TRUE && FALSE)", (TRUE && FALSE), FALSE);
   ensureIntegerEqual("(FALSE && TRUE)", (FALSE && TRUE), FALSE);
   ensureIntegerEqual("(FALSE && FALSE)", (FALSE && FALSE), FALSE);

   // and
   ensureIntegerEqual("(1 && 2)", (1 && 2), TRUE);
   ensureIntegerEqual("(1 && 0)", (1 && 0), FALSE);
   ensureIntegerEqual("(0 && 2)", (0 && 2), FALSE);
   ensureIntegerEqual("(0 && 0)", (0 && 0), FALSE);


   // or
   ensureIntegerEqual("(TRUE || TRUE)", (TRUE || TRUE), TRUE);
   ensureIntegerEqual("(TRUE || FALSE)", (TRUE || FALSE), TRUE);
   ensureIntegerEqual("(FALSE || TRUE)", (FALSE || TRUE), TRUE);
   ensureIntegerEqual("(FALSE || FALSE)", (FALSE || FALSE), FALSE);

   // or
   ensureIntegerEqual("(1 || 2)", (1 || 2), TRUE);
   ensureIntegerEqual("(1 || 0)", (1 || 0), TRUE);
   ensureIntegerEqual("(0 || 2)", (0 || 2), TRUE);
   ensureIntegerEqual("(0 || 0)", (0 || 0), FALSE);

   // not
   ensureIntegerEqual("(! TRUE)", (! TRUE), FALSE);
   ensureIntegerEqual("(! FALSE)", (! FALSE), TRUE);

   // not 
   ensureIntegerEqual("(! 2)", (! 2), FALSE);
   ensureIntegerEqual("(! 0)", (! 0), TRUE);


   // greater than
   ensureIntegerEqual("(1 > 0)", (1 > 0), TRUE);
   ensureIntegerEqual("(0 > 1)", (0 > 1), FALSE);
   ensureIntegerEqual("(1 > 1)", (1 > 1), FALSE);

   // less than
   ensureIntegerEqual("(0 < 1)", (0 < 1), TRUE);
   ensureIntegerEqual("(1 < 0)", (1 < 0), FALSE);
   ensureIntegerEqual("(1 < 1)", (1 < 1), FALSE);

   // greater than or equal
   ensureIntegerEqual("(1 >= 0)", (1 >= 0), TRUE);
   ensureIntegerEqual("(0 >= 1)", (0 >= 1), FALSE);
   ensureIntegerEqual("(1 >= 1)", (1 >= 1), TRUE);

   // tess than or equal
   ensureIntegerEqual("(0 <= 1)", (0 <= 1), TRUE);
   ensureIntegerEqual("(1 <= 0)", (1 <= 0), FALSE);
   ensureIntegerEqual("(1 <= 1)", (1 <= 1), TRUE);

   // bitwise and
   ensureIntegerEqual("(10 & 25)", (10 & 25), 8);

   // bitwise or
   ensureIntegerEqual("(10 | 25)", (10 | 25), 27);

   // bitwise not
   ensureIntegerEqual("~10", ~10, -11);

   // xor
   ensureIntegerEqual("(10 ^ 25)", (10 ^ 25), 19);

   // right shift
   ensureIntegerEqual("(523 >> 2)", (523 >> 2), 130);

   // left shift
   ensureIntegerEqual("(523 << 2)", (523 << 2), 2092);

   // addition
   ensureIntegerEqual("(1 + 1)", (1 + 1), 2);
   ensureFloatEqual("(1 + 1.1)", (1 + 1.1), 2.1);
   ensureFloatEqual("(1.1 + 1)", (1.1 + 1), 2.1);
   ensureFloatEqual("(1.1 + 1.1)", (1.1 + 1.1), 2.2);
   ensureStringEqual("\"foo\" + \"bar\"", "foo" + "bar", "foobar");
   ensureVectorEqual("(<1.1, 2.2, 3.3> + <4.4, 5.5, 6.6>)", (<1.1, 2.2, 3.3> + <4.4, 5.5, 6.6>), <5.5, 7.7, 9.9>);
   ensureRotationEqual("(<1.1, 2.2, 3.3, 4.4> + <4.4, 5.5, 6.6, 3.3>)", (<1.1, 2.2, 3.3, 4.4> + <4.4, 5.5, 6.6, 3.3>), <5.5, 7.7, 9.9, 7.7>);
   ensureListEqual("([1] + 2)", ([1] + 2), [1,2]);
   ensureListEqual("([] + 1.5)", ([] + 1.5), [1.5]);
   ensureListEqual("([\"foo\"] + \"bar\")", (["foo"] + "bar"), ["foo", "bar"]);
   ensureListEqual("([] + <1,2,3>)", ([] + <1,2,3>), [<1,2,3>]);
   ensureListEqual("([] + <1,2,3,4>)", ([] + <1,2,3,4>), [<1,2,3,4>]);

   ensureListEqual("(1 + [2])", (1 + [2]), [1,2]);
   ensureListEqual("(1.0 + [2])", (1.0 + [2]), [1.0,2]);
   ensureListEqual("(1 + [2])", ("one" + [2]), ["one",2]);
   ensureListEqual("(<1.0,1.0,1.0,1.0> + [2])", (<1.0,1.0,1.0,1.0> + [2]), [<1.0,1.0,1.0,1.0>,2]);
   ensureListEqual("(<1.0,1.0,1.0> + [2])", (<1.0,1.0,1.0> + [2]), [<1.0,1.0,1.0>,2]);


   // subtraction
   ensureIntegerEqual("(1 - 1)", (1 - 1), 0);
   ensureFloatEqual("(1 - 0.5)", (1 - 0.5), 0.5);
   ensureFloatEqual("(1.5 - 1)", (1.5 - 1), 0.5);
   ensureFloatEqual("(2.2 - 1.1)", (2.2 - 1.1), 1.1);
   ensureVectorEqual("(<1.5, 2.5, 3.5> - <4.5, 5.5, 6.5>)", (<1.5, 2.5, 3.5> - <4.5, 5.5, 6.5>), <-3.0, -3.0, -3.0>);
   ensureRotationEqual("(<1.5, 2.5, 3.5, 4.5> - <4.5, 5.5, 6.5, 7.5>)", (<1.5, 2.5, 3.5, 4.5> - <4.5, 5.5, 6.5, 7.5>), <-3.0, -3.0, -3.0, -3.0>);

   // multiplication
   ensureIntegerEqual("(2 * 3)", (2 * 3), 6);
   ensureFloatEqual("(2 * 3.5)", (2 * 3.5), 7.0);
   ensureFloatEqual("(2.5 * 3)", (2.5 * 3), 7.5);
   ensureFloatEqual("(2.5 * 3.5)", (2.5 * 3.5), 8.75);
   ensureVectorEqual("(<1.1, 2.2, 3.3> * 2)", (<1.1, 2.2, 3.3> * 2), <2.2, 4.4, 6.6>);
   ensureVectorEqual("(2 * <1.1, 2.2, 3.3>)", (<1.1, 2.2, 3.3> * 2), (2 * <1.1, 2.2, 3.3>));
   ensureVectorEqual("(<2.2, 4.4, 6.6> * 2.0)", (<2.2, 4.4, 6.6> * 2.0), <4.4, 8.8, 13.2>);
   ensureVectorEqual("(2.0 * <2.2, 4.4, 6.6>)", (<2.2, 4.4, 6.6> * 2.0), (2.0 * <2.2, 4.4, 6.6>));
   ensureFloatEqual("<1,3,-5> * <4,-2,-1>", <1,3,-5> * <4,-2,-1>, 3.0);
   ensureVectorEqual("<-1,0,0> * <0, 0, 0.707, 0.707>", <-1,0,0> * <0, 0, 0.707, 0.707>, <0,-1, 0>);
   ensureRotationEqual("(<1.0, 2.0, 3.0, 4.0> * <5.0, 6.0, 7.0, 8.0>)", (<1.0, 2.0, 3.0, 4.0> * <5.0, 6.0, 7.0, 8.0>), <32.0, 32.0, 56.0, -6.0>);


   // division
   ensureIntegerEqual("(2 / 2)", (2 / 2), 1);
   ensureFloatEqual("(2.2 / 2)", (2.2 / 2), 1.1);
   ensureFloatEqual("(3 / 1.5)", (3 / 1.5), 2.0);
   ensureFloatEqual("(2.2 / 2.0)", (2.2 / 2.0), 1.1);
   ensureVectorEqual("(<1.0, 2.0, 3.0> / 2)", (<1.0, 2.0, 3.0> / 2), <0.5, 1.0, 1.5>);
   ensureVectorEqual("(<3.0, 6.0, 9.0> / 1.5)", (<3.0, 6.0, 9.0> / 1.5), <2.0, 4.0, 6.0>);
   ensureVectorEqual("<-1,0,0> / <0, 0, 0.707, 0.707>", <-1,0,0> / <0, 0, 0.707, 0.707>, <0,1, 0>);
   ensureRotationEqual("(<1.0, 2.0, 3.0, 4.0> / <5.0, 6.0, 7.0, 8.0>)", (<1.0, 2.0, 3.0, 4.0> / <5.0, 6.0, 7.0, 8.0>), <-16.0, 0.0, -8.0, 70.0>);

   // modulo
   ensureIntegerEqual("(3 % 1)", (3 % 1), 0);
   ensureVectorEqual("(<1.0, 2.0, 3.0> % <4.0, 5.0, 6.0>)", (<1.0, 2.0, 3.0> % <4.0, 5.0, 6.0>), <-3.0, 6.0, -3.0>);

   // assignment
   integer i = 1;
   ensureIntegerEqual("i = 1;", i, 1);

   // addition assignment
   i = 1;
   i += 1;
   ensureIntegerEqual("i = 1; i += 1;", i, 2);

   // subtraction assignment
   i = 1;
   i -= 1;
   ensureIntegerEqual("i = 1; i -= 1;", i, 0);

   // multiplication assignment integer *= integer
   i = 2;
   i *= 2;
   ensureIntegerEqual("i = 2; i *= 2;", i, 4);

   // multiplication assignment integer *= float
   i = 1;
   i *= 0.5;
   ensureIntegerEqual("i = 1; i *= 0.5;", i, 0);

   // division assignment
   i = 2;
   i /= 2;
   ensureIntegerEqual("i = 2; i /= 2;", i, 1);
   
   // check overflow behaviour
   i = 0x80000000 / -1;
   ensureIntegerEqual("i = 0x80000000 / -1;", i, -2147483648);

   // modulo assignment
   i = 3;
   i %= 1;
   ensureIntegerEqual("i = 3; i %= 1;", i, 0);

   // check overflow behaviour
   i = 0x80000000 % -1;
   ensureIntegerEqual("i = 0x80000000 & -1;", i, 0);

   // post increment.
   i = 1;
   ensureIntegerEqual("i = 1; (i == 2) && (i++ == 1)", (i == 2) && (i++ == 1), TRUE);

   // pre increment.
   i = 1;
   ensureIntegerEqual("i = 1; (i == 2) && (++i == 2)", (i == 2) && (++i == 2), TRUE);

   // post decrement.
   i = 2;
   ensureIntegerEqual("i = 2; (i == 1) && (i-- == 2)", (i == 1) && (i-- == 2), TRUE);

   // pre decrement.
   i = 2;
   ensureIntegerEqual("i = 2; (i == 1) && (--i == 1)", (i == 1) && (--i == 1), TRUE);
   i = 2; --i;
   ensureIntegerEqual("i = 2; --i", i, 1);

   // casting
   ensureFloatEqual("((float)2)", ((float)2), 2.0);
   ensureStringEqual("((string)2)", ((string)2), "2");
   ensureIntegerEqual("((integer) 1.5)", ((integer) 1.5), 1);
   ensureStringEqual("((string) 1.5)", ((string) 1.5), "1.500000");
   ensureIntegerEqual("((integer) \"0xF\")", ((integer) "0xF"), 15);
   ensureIntegerEqual("((integer) \"2\")", ((integer) "2"), 2);
   ensureFloatEqual("((float) \"1.5\")", ((float) "1.5"), 1.5);
   ensureVectorEqual("((vector) \"<1,2,3>\")", ((vector) "<1,2,3>"), <1,2,3>);
   ensureRotationEqual("((quaternion) \"<1,2,3,4>\")", ((quaternion) "<1,2,3,4>"), <1,2,3,4>);
   ensureStringEqual("((string) <1,2,3>)", ((string) <1,2,3>), "<1.00000, 2.00000, 3.00000>");
   ensureStringEqual("((string) <1,2,3,4>)", ((string) <1,2,3,4>), "<1.00000, 2.00000, 3.00000, 4.00000>");
   ensureStringEqual("((string) [1,2.5,<1,2,3>])", ((string) [1,2.5,<1,2,3>]), "12.500000<1.000000, 2.000000, 3.000000>");

   // while
   i = 0;
   while(i < 10) ++i;
   ensureIntegerEqual("i = 0; while(i < 10) ++i", i, 10);

   // do while
   i = 0;
   do {++i;} while(i < 10);
   ensureIntegerEqual("i = 0; do {++i;} while(i < 10);", i, 10);

   // for
   for(i = 0; i < 10; ++i);
   ensureIntegerEqual("for(i = 0; i < 10; ++i);", i, 10);

   // jump
   i = 1;
   jump SkipAssign;
   llSetText("Error", <1,0,0>, 1); // Inserting this library call causes a save point to be added.
   i = 2;
   @SkipAssign;
   ensureIntegerEqual("i = 1; jump SkipAssign; i = 2; @SkipAssign;", i, 1);

   // return
   ensureIntegerEqual("testReturn()", testReturn(), 1);
   ensureFloatEqual("testReturnFloat()", testReturnFloat(), 1.0);
   ensureStringEqual("testReturnString()", testReturnString(), "Test string");
   ensureVectorEqual("testReturnVector()", testReturnVector(), <1,2,3>);
   ensureRotationEqual("testReturnRotation()", testReturnRotation(), <1,2,3,4>);
   ensureVectorEqual("testReturnVectorNested()", testReturnVectorNested(), <1,2,3>);
   ensureVectorEqual("testReturnVectorWithLibraryCall()", testReturnVectorWithLibraryCall(), <1,2,3>);
   ensureRotationEqual("testReturnRotationWithLibraryCall()", testReturnRotationWithLibraryCall(), <1,2,3,4>);

   // parameters
   ensureIntegerEqual("testParameters(1)", testParameters(1), 2);

   // variable parameters
   i = 1;
   ensureIntegerEqual("i = 1; testParameters(i)", testParameters(i), 2);

   // recursion
   ensureIntegerEqual("testRecursion(10)", testRecursion(10), 0);

   // globals
   ensureIntegerEqual("gInteger", gInteger, 5);
   ensureFloatEqual("gFloat", gFloat, 1.5);
   ensureStringEqual("gString", gString, "foo");
   ensureVectorEqual("gVector", gVector, <1, 2, 3>);
   ensureRotationEqual("gRot", gRot, <1, 2, 3, 4>);
   ensureListEqual("gList", gList, [1, 2, 3]);

   // global assignment
   gInteger = 1;
   ensureIntegerEqual("gInteger = 1", gInteger, 1);

   gFloat = 0.5;
   ensureFloatEqual("gFloat = 0.5", gFloat, 0.5);

   gString = "bar";
   ensureStringEqual("gString = \"bar\"", gString, "bar");

   gVector = <3,3,3>;
   ensureVectorEqual("gVector = <3,3,3>", gVector, <3,3,3>);

   gRot = <3,3,3,3>;
   ensureRotationEqual("gRot = <3,3,3,3>", gRot, <3,3,3,3>);

   gList = [4,5,6];
   ensureListEqual("gList = [4,5,6]", gList, [4,5,6]);

   // negation
   gVector = <3,3,3>;
   ensureVectorEqual("-gVector = <-3,-3,-3>", -gVector, <-3,-3,-3>);

   gRot = <3,3,3,3>;
   ensureRotationEqual("-gRot = <-3,-3,-3,-3>", -gRot, <-3,-3,-3,-3>);


   // vector accessor
   vector v;
   v.x = 3;
   ensureFloatEqual("v.x", v.x, 3);

   // rotation accessor
   rotation q;
   q.s = 5;
   ensureFloatEqual("q.s", q.s, 5);

   // global vector accessor
   gVector.y = 17.5;
   ensureFloatEqual("gVector.y = 17.5", gVector.y, 17.5);

   // global rotation accessor
   gRot.z = 19.5;
   ensureFloatEqual("gRot.z = 19.5", gRot.z, 19.5);

   // list equality
   list l = (list) 5;
   list l2 = (list) 5;
   ensureListEqual("list l = (list) 5; list l2 = (list) 5", l, l2);
   ensureListEqual("list l = (list) 5", l, [5]);
   ensureListEqual("[1.5, 6, <1,2,3>, <1,2,3,4>]", [1.5, 6, <1,2,3>, <1,2,3,4>], [1.5, 6, <1,2,3>, <1,2,3,4>]);

   // String escaping
   ensureIntegerEqual("llStringLength(\"\\\") == 1", llStringLength("\\"), 1);
   ensureIntegerEqual("llStringLength(\"\\t\") == 4", llStringLength("\t"), 4);
   ensureIntegerEqual("llStringLength(\"\\n\") == 1", llStringLength("\n"), 1);
   ensureIntegerEqual("llStringLength(\"\\\"\") == 1", llStringLength("\""), 1);

   // Nested expression lists
   ensureStringEqual("testExpressionLists([testExpressionLists([]), \"bar\"]) == \"foofoobar\"", testExpressionLists([testExpressionLists([]), "bar"]), "foofoobar");

}

default {

   touch_start(integer total_number)
   {
       llResetTime();
       tests();
       llSay(0, "Ran " + (string)(gTestsPassed + gTestsFailed) + " tests in " + (string) llGetTime() + " seconds with " + (string)gTestsFailed + " failures");

       // reset globals  
       gInteger = 5;
       gFloat = 1.5;
       gString = "foo";
       gVector = <1, 2, 3>;
       gRot = <1, 2, 3, 4>;
       gList = [1, 2, 3];
       gTestsPassed = 0;
       gTestsFailed = 0;
   }

   http_response(key request_id, integer status, list metadata, string body)
   {

   }

}</lsl>