/*
Copyright (C) 2014-2015 Runtime Revolution Ltd.

This file is part of LiveCode.

LiveCode is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License v3 as published by the Free
Software Foundation.

LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with LiveCode.  If not see <http://www.gnu.org/licenses/>.  */

module Test

use com.livecode.math
use com.livecode.file
use com.livecode.stream
use com.livecode.system
use com.livecode.date

public handler Test()
    variable tResults as List
    put the empty list into tResults
    	testFile(tResults)

    variable tDelimiter as String
    put newline into tDelimiter
	

	-- test test
	testLog("__Test", "Fail", false, tResults)
	testLog("__Test", "Succeed", true, tResults)
	
	-- structural
	testRepeat(tResults)
	testLogicStructural(tResults)
    testPrecedence(tResults)
    
    testParseAndFormat(tResults)

    --com.livecode.type
    testType(tResults)

	--com.livecode.array
	testArray(tResults)	
	
	--com.livecode.typeconvert
	testTypeConvert(tResults)
	
	--com.livecode.list
    testList(tResults)
    
	--com.livecode.arithmetic
    testArithmetic(tResults)
    	
	--com.livecode.bitwise	
	testBitwise(tResults)
	
	--com.livecode.char
	testChar(tResults)
		
	--com.livecode.logic
    testLogic(tResults)
    
	--com.livecode.math
	testMath(tResults)
	
	--com.livecode.mathfoundation
	testMathFoundation(tResults)
	
	--com.livecode.sort
    testSort(tResults)
    
	--com.livecode.string
	testString(tResults)
	
	--com.livecode.type
	testType(tResults)
	
	--com.livecode.file
	testFile(tResults)

	--com.livecode.stream
	testStream(tResults)

	--com.livecode.system
	testSystem(tResults)

	--com.livecode.date
	testDate(tResults)
	
	--com.livecode.binary
	--com.livecode.byte
	--com.livecode.item
	--com.livecode.line
	--com.livecode.segmentchunk

    return newline & testSummary (tResults)

end handler

/*
Summary: Summarises the results of a test into a string

Parameters:
pResults: The list of test results
*/
public handler testSummary(in pResults as List)
    variable tSuccessCount as Integer
    variable tFailureCount as Integer
    variable tSummaryItems as List

    put 0 into tSuccessCount
    put 0 into tFailureCount
    put the empty list into tSummaryItems

    variable tReport as String
    repeat for each element tReport in pResults
        if tReport begins with "SUCCESS" then
            add 1 to tSuccessCount
            next repeat
        end if
        add 1 to tFailureCount
        push tReport onto tSummaryItems
    end repeat

    push tFailureCount converted to base 10 && "TESTS FAILED (" & tSuccessCount converted to base 10 && "PASSED)" onto tSummaryItems

    variable tSummaryString as String
    combine tSummaryItems with newline
    put the result into tSummaryString

    return tSummaryString
end handler

/*
Summary: Logs the result of a test to the <xResults> list

Parameters:
pModule: The name of the module this test comes from.
pTest: The name of the test.
pResult: The result of the test
xResults: The ongoing list of test results

Description:
Pushes either the string "SUCCESS : <pModule>_<pTest>" or the string "FAILURE : <pModule>_<pTest>" onto the results list,
depending on the value of <pResult>

*/
public handler testLog(in pModule as String, in pTest as String, in pResult as Boolean, inout xResults as List)
    variable tStringResult as String
    if pResult then
        put "SUCCESS" into tStringResult
    else
        put "FAILURE" into tStringResult
    end if

    push tStringResult && ":" && pModule & "_" & pTest onto xResults
end handler

public handler boolWithSideEffect(in tResult as Boolean, inout tVar as String) as Boolean
	put "a" into tVar
	return tResult
end handler

public handler testParseAndFormat(inout xResults as List)

	// some formatting tests will fail until we have
	// context vars (number format) and distinct reals/ints
	
	testLog("Arithmetic", "StringParsedAsNumber", "1.5" parsed as number is 1.5, xResults)

	variable tInt as Integer
	put 3 into tInt
	testLog("Arithmetic", "NumberFormattedAsString", tInt formatted as string is "3", xResults)

	variable tVar as optional Number
	put "dfsdf" parsed as number into tVar

	testLog("Arithmetic", "StringParsedAsNumberFail", tVar is not defined, xResults)
	
	variable tList as List
	put ["1", "b", "3"] parsed as list of number into tList
	
	variable tElt as Number
	repeat with tElt from 1 up to the number of elements in tList
		if tList[tElt] is not defined then
			put 0 into element tElt of tList
		end if
	end repeat

	testLog("Arithmetic", "ListOfStringParsedAsListOfNumberFail", tList is [ 1, 0, 3 ], xResults)
	testLog("Arithmetic", "ListOfStringParsedAsListOfNumber", ["1", "2", "3"] parsed as list of number is [ 1, 2, 3 ], xResults)
	
	parse "0.5" as number
	testLog("Arithmetic", "ParseAsNumber", the result is 0.5, xResults)
	
	testLog("Logic", "ParseAsBool", "true" parsed as boolean, xResults)
	testLog("Logic", "ParseAsBool2", not "false" parsed as boolean, xResults)
	
	variable tBool
	put "sdgfds" parsed as boolean into tBool
	testLog("Logic", "ParseAsBoolFail", tBool is not defined, xResults)
	
end handler

public handler testType(inout xResults as List)

    variable tVar
    testLog("Type", "IsNotDefined", tVar is not defined, xResults)

    variable tString as String
    put "" into tString
    testLog("Type", "IsDefined", tString is defined, xResults)
    testLog("Type", "IsEmpty", tString is empty, xResults)

    put "a" after tString
    testLog("Type", "IsNotEmpty", tString is not empty, xResults)

end handler

public handler testPrecedence(inout xResults as List)

    testLog("Precedence", "Tan,Over,LessThan", the tangent of pi / 4 < 0.00000000001, xResults)

end handler

public handler testMathFoundation(inout xResults as List)

	variable tNum as Number
	put -5.5 into tNum
	
	testLog("MathFoundation", "FloorNum", the floor of tNum is -6, xResults)
	
	testLog("MathFoundation", "CeilNum", the ceiling of tNum is -5, xResults)
	
	round tNum
	
	testLog("MathFoundation", "RoundToNearestNum", tNum is -6, xResults)
	
	testLog("MathFoundation", "RoundedToNearest", the rounded of 4.5 is 5, xResults)

end handler

public handler testMath(inout xResults as List)

	testLog("Math", "PowerOf", 3 ^ 4 = 81, xResults)
	testLog("Math", "Base10Log", the log of 1000 is 3, xResults)

	// trig functions
	testLog("Math", "Sin", sin(pi / 2) is 1, xResults)	
	testLog("Math", "Sin", the sine of (pi / 2) is 1, xResults)
	
	testLog("Math", "Cos", cos(pi) is -1, xResults)
	testLog("Math", "Cos", the cosine of pi is -1, xResults)

	testLog("Math", "Tan", the tangent of (pi / 4) - 1 < 0.00000000001, xResults)
	testLog("Math", "Tan", tan(pi / 4) - 1 < 0.00000000001, xResults)

	// inverse trig functions
	testLog("Math", "Arcsin", the arcsine of 1 is pi / 2, xResults)
	testLog("Math", "Arcsin", asin(1) is pi / 2, xResults)

	testLog("Math", "Arccos", acos(-1) is pi, xResults)		
	testLog("Math", "Arccos", the arccosine of -1 is pi, xResults)

	testLog("Math", "Arctan", atan(1) is pi / 4, xResults)	
	testLog("Math", "Arctan", the arctangent of 1 is pi / 4, xResults)
	
	testLog("Math", "Arctan2", atan2(-1,-1) is -3 * pi / 4, xResults)
	testLog("Math", "Arctan2", the binary arctangent of -1 and -1 is -3 * pi / 4, xResults)


	testLog("Math", "Exp", the exponential of 3 > 20, xResults)
	testLog("Math", "Exp", the exponential of 3 < 20.1, xResults)
	
	testLog("Math", "Ln", the natural log of 55 > 4, xResults)
	testLog("Math", "Ln", the natural log of 55 < 4.01, xResults)
	
	testLog("Math", "ExpLog", the abs of the natural log of the exponential of 3 - 3 < 0.00000000001, xResults)
	testLog("Math", "LogExp", the abs of the exponential of the natural log of 80 - 80 < 0.00000000001, xResults)
	
	testLog("Math", "Trunc", the trunc of 5.5 is 5, xResults)
	
	testLog("Math", "Abs", the abs of 5.5 is 5.5, xResults)
	testLog("Math", "Abs", the abs of -5.5 is 5.5, xResults)
	
	variable tNum
	put any number into tNum
	testLog("Math", "RandomRangeLower", tNum >= 0, xResults)
	testLog("Math", "RandomRangeHigher", tNum <= 1, xResults)
	
	testLog("Math", "RandomMatch", tNum is not any number, xResults)

	variable tLeft as Integer
	variable tRight as Integer
	
	put 4 into tLeft
	put 5 into tRight
	
	testLog("Math", "Min", the minimum of 3 and 5 is 3, xResults)
	testLog("Math", "Min", min(5.5,5.4) is 5.4, xResults)

	testLog("Math", "Min", the minimum value of [5,4,1,3,2] is 1, xResults)
	
	testLog("Math", "MinInt", the minimum of tLeft and tRight is tLeft, xResults)
	testLog("Math", "MinInt", min(tRight,tLeft) is tLeft, xResults)
	
	testLog("Math", "Max", the maximum of 3 and 5 is 5, xResults)
	testLog("Math", "Max", max(5.5,5.4) is 5.5, xResults)
	
	testLog("Math", "MaxInt", the maximum of tLeft and tRight is tRight, xResults)
	testLog("Math", "MaxInt", max(tRight,tLeft) is tRight, xResults)

	testLog("Math", "ConvertFromBase", "6A" converted from base 16 is 106, xResults)
	testLog("Math", "ConvertFromBase", "1001010" converted from base 2 is 74, xResults)
	
	testLog("Math", "ConvertToBase", 7 converted to base 2 is "111", xResults)
	testLog("Math", "ConvertToBase", 500 converted to base 12 is "358", xResults)
	
	testLog("Math", "ConvertFromBaseToBase", "1122" converted from base 4 to base 14 is "66", xResults)

end handler

public handler testTypeConvert(inout xResults as List)
	variable tString as String
	put "a,b,c,d,e" into tString
	
	variable tList as List
	split tString by ","
    put the result into tList
	
	testLog("TypeConvert", "Split", tList is ["a","b", "c", "d", "e"], xResults)
	
	combine tList with ","
    put the result into tString
	
	testLog("TypeConvert", "Combine", tString is "a,b,c,d,e", xResults)
	
end handler

public handler testRepeat(inout xResults as List)

	variable tString as String
	put "abcdefghijklmno" into tString
	
	variable tRestring as String
	variable tChar as String
	put "" into tRestring
	repeat for each char tChar in tString
		put tChar after tRestring
	end repeat
	
	testLog("Repeat", "RepeatChar", tString is tRestring, xResults)
	
	variable tList as List
	put [1, 1, 2, 3, 5, 8, 13] into tList
	
	variable tRelist as List
	variable tElement as any
	put the empty list into tRelist
	repeat for each element tElement in tList
		push tElement onto tRelist
	end repeat
	
	testLog("Repeat", "RepeatElement", tRelist contains tList and tList contains tRelist, xResults)

end handler

public handler testString(inout xResults as List)
	variable tString as String
	put the empty string into tString
	
	testLog("String", "EmptyString", tString is "", xResults)
	
	put "abcde" before tString
	testLog("String", "PutBeforeString", tString is "abcde", xResults)
	
	put "fghij" after tString
	testLog("String", "PutBeforeString", tString is "abcdefghij", xResults)
	
	testLog("String", "ConcatenateString", tString is "abcde" & "fghij", xResults)
	testLog("String", "ConcatenateString", "a" & "b" & "c" is "abc", xResults)
	
	testLog("String", "ConcatenateWithSpace", "ab" && "cd" is "ab cd", xResults)
	testLog("String", "ConcatenateWithSpace", "a" && "b" && "c" is "a b c", xResults)
	
	put "purple" into tString
	replace "p" with "t" in tString
	testLog("String", "ReplaceString", tString is "turtle", xResults)
	
	testLog("String", "Uppercase", the upper of "abcd" is "ABCD", xResults)
	testLog("String", "Lowercase", the lower of "ABCD" is "abcd", xResults)
	
	testLog("String", "LessThan", "!" < "A", xResults)
	testLog("String", "GreaterThan", "a" > "A", xResults)

end handler

public handler testArray(inout xResults as List)
	variable tArray as Array
	put the empty array into tArray
	
	put "value1" into tArray["key1"]
	put "value2" into tArray["key2"]
	put "value3" into tArray["key3"]
	
	testLog("Array", "CountElementsOf", the number of elements in tArray is 3, xResults)
	
	variable tKeys as List
	put the keys of tArray into tKeys
	
	testLog("Array", "KeysOfCount", the number of elements in tKeys is 3, xResults)

	variable tKeysString as String
	combine tKeys with ","
    put the result into tKeysString
	
	testLog("Array", "KeysOf1", tKeysString contains "key1", xResults)
	testLog("Array", "KeysOf2", tKeysString contains "key2", xResults)
	testLog("Array", "KeysOf3", tKeysString contains "key3", xResults)
		
	variable tElements as List
	put the elements of tArray into tElements
	
	testLog("Array", "ElementssOfCount", the number of elements in tElements is 3, xResults)
	
	testLog("Array", "ElementsOf1", "value1" is in tElements, xResults)
	testLog("Array", "ElementsOf2", "value2" is in tElements, xResults)
	testLog("Array", "ElementsOf3", "value3" is in tElements, xResults)
		
	testLog("Array", "IsAmongTheKeys", "key1" is among the keys of tArray, xResults)
	testLog("Array", "IsAmongTheElements", "value1" is among the elements of tArray, xResults)
	
	testLog("Array", "SingletonElementOf", tArray["key1"] is "value1", xResults)

    variable tNewArray as Array
    put the empty array into tNewArray
    put 1 into tNewArray["abc"]
    put 2 into tNewArray["def"]
    put 3 into tNewArray["ghi"]

	variable tString as String
	put "" into tString
	
	variable tKey as String
    repeat for each key tKey in tNewArray
        put tKey after tString
    end repeat
    
    testLog("Array", "RepeatForEachKey1", tString contains "abc", xResults)
    testLog("Array", "RepeatForEachKey2", tString contains "def", xResults)
    testLog("Array", "RepeatForEachKey3", tString contains "ghi", xResults)

	variable tSum as Number
	put 0 into tSum
	
	variable tElement
    repeat for each element tElement in tNewArray
        add tElement to tSum
    end repeat
    
    testLog("Array", "RepeatForEachElement", tSum is 6, xResults)

	variable tTest as Array
	put the empty array into tTest
	put "value" into tTest["key"]

	delete tTest["key"]
	
	testLog("Array", "DeleteElement", the number of elements in tTest is 0, xResults)
	
	variable tArrayWithUndefined as Array
	put the empty array into tArrayWithUndefined
	put undefined into tArrayWithUndefined["a"]
	variable tUndefined
 	put tArrayWithUndefined["a"] into tUndefined
	testLog("Array", "UndefinedElement", tUndefined is not defined, xResults)
end handler

public handler testBitwise(inout xResults as List)
	variable tVar as Integer
	
	put 3 bitwise and 6 into tVar
	testLog("Bitwise", "BitwiseAnd", tVar is 2, xResults)
	
	put 3 bitwise or 6 into tVar
	testLog("Bitwise", "BitwiseOr", tVar is 7, xResults)
	
	put 3 bitwise xor 6 into tVar
	testLog("Bitwise", "BitwiseXor", tVar is 5, xResults)
	
	put bitwise not 5 into tVar
	testLog("Bitwise", "BitwiseNot", tVar is - 6, xResults)

	put 7 shifted left by 2 bitwise into tVar 
	testLog("Bitwise", "BitwiseShift", tVar is 28, xResults)
	
end handler

public handler testLogic(inout xResults as List)

    testLog("Logic", "Not", not false, xResults)
    testLog("Logic", "Not", not not true, xResults)
        
    testLog("Logic", "Is", true is true, xResults)
    testLog("Logic", "Is", false is false, xResults)

    testLog("Logic", "Is", true is not false, xResults)
    testLog("Logic", "Is", false is not true, xResults)
    	
    testLog("Logic", "Is", not true is false, xResults)
    testLog("Logic", "Is", not false is true, xResults)

    testLog("Logic", "Format", false formatted as string is "false", xResults)

    format true as string
    testLog("Logic", "Format", the result is "true", xResults)

    testLog("Logic", "Parse", "true" parsed as boolean, xResults)
    parse "false" as boolean
    testLog("Logic", "Parse", not the result, xResults)

end handler

public handler testLogicStructural(inout xResults as List)
    variable tString as String
    put the empty string into tString
    if (false and boolWithSideEffect(true, tString)) then
    	testLog("Logic", "And", false, xResults)
    else
        testLog("Logic", "And", true, xResults)
    end if	
    
    testLog("Logic", "AndShortCut", not (tString is "a"), xResults)
    
    if (true and boolWithSideEffect(true, tString)) then
    	testLog("Logic", "And", true, xResults)
    else
      	testLog("Logic", "And", false, xResults)  
    end if		
    
    testLog("Logic", "AndShortCut", tString is "a", xResults)
    
    variable tString2 as String
    put the empty string into tString2
    if (true or boolWithSideEffect(false, tString2)) then
    	testLog("Logic", "Or", true, xResults)
    else
        testLog("Logic", "Or", false, xResults)	
    end if	
    
    testLog("Logic", "OrShortCut", not (tString2 is "a"), xResults)
    
    if (false or boolWithSideEffect(false, tString2)) then
    	testLog("Logic", "Or", false, xResults)
    else
    	testLog("Logic", "Or", true, xResults)
    end if		
    
    testLog("Logic", "OrShortCut", tString2 is "a", xResults)	
end handler

public handler testChar(inout xResults as List)
	variable tString as String
	put "abcde" into tString
	
	testLog("Char", "CountCharsOf", the number of chars in tString is 5, xResults)
	testLog("Char", "FetchCharOf", char 5 of tString is "e", xResults)
	
	put "abcd" into char 5 of tString
	
	testLog("Char", "StoreCharOf", tString is "abcdabcd", xResults)
	
	testLog("Char", "FetchCharRangeOf", char 5 to 8 of tString is "abcd", xResults)
	
	put "e" into char 5 to 8 of tString
	
	testLog("Char", "StoreCharRangeOf", tString is "abcde", xResults)
	
	testLog("Char", "CharIsIn", "a" is in "abc", xResults)

	put "abcde" before char 1 of tString
	
	testLog("Char", "BeforeCharOf", tString is "abcdeabcde", xResults)
	
	put "abcde" after char 5 of tString
	
	testLog("Char", "AfterCharOf", tString is "abcdeabcdeabcde", xResults)
	
	testLog("Char", "BeginsWithEmpty", tString begins with "", xResults)
	testLog("Char", "BeginsWith", tString begins with "abcd", xResults)
	
	testLog("Char", "EndsWithEmpty", tString ends with "", xResults)
	testLog("Char", "EndsWith", tString ends with "bcde", xResults)

	variable tOffset as Integer
	put the first offset of "abcde" in tString into tOffset
	
	testLog("Char", "CharOffset", tOffset is 1, xResults)
	
	put the first offset of "abcdef" in tString into tOffset
	testLog("Char", "CharOffset", tOffset is 0, xResults)

	/* bug 14846
	put the offset of "abcde" after 1 in tString into tOffset
	
	testLog("Char", "CharOffsetAfter", tOffset is 5, xResults)
	
	put the first offset of "abcde" after 11 in tString into tOffset
	testLog("Char", "CharOffsetAfter", tOffset is 0, xResults)
	
	variable tLastDot as Integer
	variable tAddress as String
	variable tTLD as String
	put "http://www.livecode.com/index.html" into tAddress
	put the last offset of "." in tAddress into tLastDot
	put the offset of "." before tLastDot in tAddress into tOffset
	put char tOffset + 1 to tOffset + 3 of tAddress into tTLD
	
	testLog("Char", "CharOffsetBefore", tTLD is "com", xResults)
	*/

	variable tVar as String
	put "123" into tVar
	
	variable tCount as Integer
	put the number of chars in tVar into tCount
	subtract 1 from tCount
	
	repeat tCount times
		put "," after char tCount of tVar
		subtract 1 from tCount
	end repeat 	
	
	testLog("Char", "CharExample", tVar is "1,2,3", xResults)

    variable tTest as String
    put "abc" into tTest

    put "X" into char 1 of tTest
    testLog("Char", "FirstCharFetch", the first char of tTest is "X", xResults)

    put "a" into the first char of tTest
    testLog("Char", "FirstCharStore", char 1 of tTest is "a", xResults)
    
    put "Z" into char -1 of tTest
    testLog("Char", "LastCharFetch", the last char of tTest is "Z", xResults)

    put "c" into the last char of tTest
    testLog("Char", "LastCharStore", char -1 of tTest is "c", xResults)
    
    delete char 1 of tTest
    testLog("Char", "DeleteChar", tTest is "bc", xResults)
    
    delete char 1 to 2 of tTest
    testLog("Char", "DeleteChars", tTest is the empty string, xResults)

	put "abc" into tTest

	delete the last char of tTest
	testLog("Char", "DeleteLastChar", tTest is "ab", xResults)	

	delete the first char of tTest
	testLog("Char", "DeleteFirstChar", tTest is "b", xResults)	

end handler

public handler testArithmetic(inout xResults as List)

	variable tInt as Number
	variable tReal as Number
	variable tNumber
	
	put 10 into tInt
	put 10 into tReal
	put 10 into tNumber
	
	add 2 to tInt
	add 2 to tReal
	add 2 to tNumber
	
	testLog("Arithmetic", "AddToInt", tInt is 12, xResults)
	testLog("Arithmetic", "AddToReal", tReal is 12, xResults)
	testLog("Arithmetic", "AddToNum", tNumber is 12, xResults)

	subtract 2 from tInt
	subtract 2 from tReal
	subtract 2 from tNumber
	
	testLog("Arithmetic", "SubtractFromInt", tInt is 10, xResults)
	testLog("Arithmetic", "SubtractFromReal", tReal is 10, xResults)
	testLog("Arithmetic", "SubtractFromNum", tNumber is 10, xResults)
	
	multiply tInt by 2
	multiply tReal by 2
	multiply tNumber by 2

	testLog("Arithmetic", "MultiplyInt", tInt is 20, xResults)
	testLog("Arithmetic", "MultiplyReal", tReal is 20, xResults)
	testLog("Arithmetic", "MultiplyNum", tNumber is 20, xResults)	

	divide tInt by 40
	divide tReal by 40
	divide tNumber by 40
	
	testLog("Arithmetic", "DivideInt", tInt is 0.5, xResults)
	testLog("Arithmetic", "DivideReal", tReal is 0.5, xResults)
	testLog("Arithmetic", "DivideNum", tNumber is 0.5, xResults)
	
	variable tLeft as Integer
	variable tRight as Integer
	
	put 10 into tLeft
	put 2 into tRight
	
	variable tLeftReal as Number
	variable tRightReal as Number
	
	put 10 into tLeftReal
	put 2 into tRightReal
	
	testLog("Arithmetic", "PlusInt", tLeft + tRight is 12, xResults)
	testLog("Arithmetic", "PlusReal", tLeftReal + tRightReal is 12, xResults)
	testLog("Arithmetic", "PlusNum", 10 + 2 is 12, xResults)
	
	testLog("Arithmetic", "MinusInt", tLeft - tRight is 8, xResults)
	testLog("Arithmetic", "MinusReal", tLeftReal - tRightReal is 8, xResults)	
	testLog("Arithmetic", "MinusNum", 10 - 2 is 8, xResults)
	
	testLog("Arithmetic", "TimesInt", tLeft * tRight is 20, xResults)
	testLog("Arithmetic", "TimesReal", tLeftReal * tRightReal is 20, xResults)
	testLog("Arithmetic", "TimesNum", 10 * 2 is 20, xResults)
	
	testLog("Arithmetic", "DivideInt", tLeft / tRight is 5, xResults)
	testLog("Arithmetic", "DivideReal", tLeftReal / tRightReal is 5, xResults)
	testLog("Arithmetic", "DivideNum", 10 / 2 is 5, xResults)
	
	variable tOne as Integer
	put 1 into tOne
	
	testLog("Arithmetic", "ModInt", tLeft mod (tRight + tOne) is 1, xResults)
	testLog("Arithmetic", "ModNum", 4^((7-1)/2) mod 7 is 1, xResults)
	
	testLog("Arithmetic", "Wrap", 5 wrap 3 is 2, xResults)
	testLog("Arithmetic", "Wrap", -3 wrap 3 is -3, xResults)
	
	testLog("Arithmetic", "GreaterThanInt", tLeft > tRight, xResults)
	testLog("Arithmetic", "GreaterThanInt", not tLeft > tLeft, xResults)
	testLog("Arithmetic", "GreaterThanNum", 2 > 1, xResults)
	testLog("Arithmetic", "GreaterThanNum", not 1 > 1, xResults)
	
	testLog("Arithmetic", "GreaterThanOrEqualToInt", tLeft >= tLeft, xResults)
	testLog("Arithmetic", "GreaterThanOrEqualToInt", not tRight >= tLeft, xResults)
	testLog("Arithmetic", "GreaterThanOrEqualToNum", 1 >= 1, xResults)
	testLog("Arithmetic", "GreaterThanOrEqualToNum", not 1 >= 2, xResults)
	
	testLog("Arithmetic", "LessThanInt", not tLeft < tLeft, xResults)
	testLog("Arithmetic", "LessThanInt", tRight < tLeft, xResults)
	testLog("Arithmetic", "LessThanNum", 1 < 2, xResults)
	testLog("Arithmetic", "LessThanNum", not 1 < 1, xResults)
	
	testLog("Arithmetic", "LessThanOrEqualToInt", tLeft <= tLeft, xResults)
	testLog("Arithmetic", "LessThanOrEqualToInt", not tLeft <= tRight, xResults)
	testLog("Arithmetic", "LessThanOrEqualToNum", 1 <= 1, xResults)
	testLog("Arithmetic", "LessThanOrEqualToNum", not 2 <= 1, xResults)
    
    testLog("Arithmetic", "CrossTypeComparison", tLeft > 5, xResults)
    testLog("Arithmetic", "CrossTypeComparison", tLeftReal > 5, xResults)
    testLog("Arithmetic", "CrossTypeComparison", tLeft >= 10, xResults)
    testLog("Arithmetic", "CrossTypeComparison", tLeftReal >= 10, xResults)
    testLog("Arithmetic", "CrossTypeComparison", tLeftReal <= tLeft, xResults)
    testLog("Arithmetic", "CrossTypeComparison", tLeft <= tLeftReal, xResults)
	
end handler

public handler testList(inout xResults as List)
    variable tTestList as List
    put the empty list into tTestList

	variable tCount as Integer
	put the number of elements in tTestList into tCount
	testLog("List", "EmptyList", tCount is 0, xResults)

    push "xyz" onto tTestList
    push 2 onto tTestList
    push "abcd" onto tTestList
    push 1 onto tTestList

    testLog("List", "NumberOfElements", the number of elements in tTestList is 4, xResults)
   	testLog("List", "HeadOf", the head of tTestList is "xyz", xResults)
	testLog("List", "TailOf", the tail of tTestList is 1, xResults)

	variable tNewList as List
	put [1,2,3] into tNewList
	push 0 onto front of tNewList
	testLog("List", "PushOntoListFront", tNewList[1] is 0, xResults)
	push 4 onto back of tNewList
	testLog("List", "PushOntoListBack", tNewList[-1] is 4, xResults)
	push 5 onto tNewList
	testLog("List", "PushOntoList", tNewList[-1] is 5, xResults)
	
	put "A" into element 2 of tNewList
    testLog("List", "ElementOf", element 2 of tNewList is "A", xResults)
   	testLog("List", "ElementRangeOf1", element 2 of element 3 to -1 of tTestList is 1, xResults)
	put "ABC" into element 2 to 4 of tNewList
	testLog("List", "ElementRangeOf2", element -3 of tNewList is "ABC", xResults)

    testLog("List", "Contains", tTestList contains element -2 to -1 of tTestList, xResults)

	testLog("List", "Begins", tTestList begins with [tTestList[1], tTestList[2]], xResults)
	testLog("List", "Ends", tTestList ends with element 3 to -1 of tTestList, xResults)

    variable tSubList as List
    put element -2 to -1 of tTestList into tSubList

	testLog("List", "Is", tSubList is ["abcd", 1], xResults)
	testLog("List", "IsNot", tSubList is not ["Abcd", 1], xResults)

    testLog("List", "IsIn", "abcd" is in ["abcd", "efgh"], xResults)
    testLog("List", "IsNotIn", not "dsf" is in ["abcd", "efgh"], xResults)

    variable tString as String
    pop front of tSubList into tString

    testLog("List", "PopList1", tString is "abcd", xResults)
    testLog("List", "PopList2", the number of elements in tSubList is 1, xResults)

	variable tElt as Number
	pop front of tNewList into tElt
	testLog("List", "PopFromFront", tElt is 0, xResults)
	pop back of tNewList into tElt
	testLog("List", "PopFromBack", tElt is 5, xResults)
	
    splice tTestList after element 1 of tSubList

    testLog("List", "SpliceAfter1", the number of elements in tSubList is 5, xResults)
    testLog("List", "SpliceAfter2", the tail of tSubList is 1, xResults)
    testLog("List", "SpliceAfter3", tSubList contains tTestList, xResults)

	put "ZZZZ" into tTestList[1]
	testLog("List", "SingletonElement", tTestList[1] is "ZZZZ", xResults)

	variable tList as List
	put [1,2,3] into tList
	
	splice tList into element 1 to 3 of tList
	testLog("List", "SpliceIntoRange", tList is [1,2,3], xResults)
	splice element 1 to 2 of tList into element 1 of tList
	testLog("List", "SpliceIntoElement", tList is [1,2,2,3], xResults)
	
	splice tList before element 1 of tList
	testLog("List", "SpliceBefore", tList is [1,2,2,3,1,2,2,3], xResults)
	
	variable tAnotherList as List
	put [1,2,3] into tAnotherList	
	put tAnotherList into element 1 to 2 of tAnotherList 
	testLog("List", "ElementRangeOf3", element -2 of tAnotherList is [1,2,3], xResults)

    variable tTest as List
    put [1,2,3] into tTest

    put "X" into element 1 of tTest
    testLog("List", "FirstElementFetch", the first element of tTest is "X", xResults)

    put 0 into the first element of tTest
    testLog("List", "FirstElementStore", element 1 of tTest is 0, xResults)
   
    put "Z" into element -1 of tTest
    testLog("List", "LastElementFetch", the last element of tTest is "Z", xResults)

    put 4 into the last element of tTest
    testLog("List", "LastElementStore", element -1 of tTest is 4, xResults)
    
    delete element 1 of tTest
    testLog("List", "DeleteElement", tTest is [2,4], xResults)
    
    delete element 1 to 2 of tTest
    testLog("List", "DeleteElements", tTest is the empty list, xResults)

	put [1,2,3] into tTest

	delete the last element of tTest
	testLog("List", "DeleteLastElement", tTest is [1,2], xResults)	

	delete the first element of tTest
	testLog("List", "DeleteFirstElement", tTest[1] is 2, xResults)	

	variable tListWithUndefined as List
	put the empty list into tListWithUndefined
	push undefined onto tListWithUndefined
	variable tUndefined
 	put the head of tListWithUndefined into tUndefined
	testLog("List", "UndefinedElement", tUndefined is not defined, xResults)
	
end handler

public handler testSort(inout xResults as List)
    variable tNumericList as List
	put [4,3,5,1,2] into tNumericList
    
    sort tNumericList in descending numeric order

    testLog("Sort", "DescendingNumeric", tNumericList is [5,4,3,2,1], xResults)
    
    sort tNumericList in ascending numeric order
    
    testLog("Sort", "AscendingNumeric", tNumericList is [1,2,3,4,5], xResults)

	variable tStringList as List
	put ["a", "c", "b"] into tStringList

    sort tStringList in ascending text order

    testLog("Sort", "AscendingText", tStringList is ["a", "b", "c"], xResults)
    
    sort tStringList in descending text order

    testLog("Sort", "DescendingText", tStringList is ["c", "b", "a"], xResults)
    
    sort tStringList
    
    testLog("Sort", "AscendingGeneric", tStringList is ["a", "b", "c"], xResults)
    
    sort tNumericList in descending order
    
    testLog("Sort", "DescendingGeneric", tNumericList is [5,4,3,2,1], xResults)
        
end handler

public handler testData(inout xResults as List)
/*
    variable tTest as String
    put "abc" into tTest

    put "X" into char 1 of tTest
    testLog("Char", "FirstCharFetch", the first char of tTest is "X", xResults)

    put "a" into the first char of tTest
    testLog("Char", "FirstCharStore", char 1 of tTest is "a", xResults)
    
    put "Z" into char -1 of tTest
    testLog("Char", "LastCharFetch", the last char of tTest is "Z", xResults)

    put "c" into the last char of tTest
    testLog("Char", "LastCharStore", char -1 of tTest is "c", xResults)
    
    delete char 1 of tTest
    testLog("Char", "DeleteChar", tTest is "bc", xResults)
    
    delete char 1 to 2 of tTest
    testLog("Char", "DeleteChars", tTest is the empty string, xResults)

	put "abc" into tTest

	delete the last char of tTest
	testLog("Char", "DeleteLastChar", tTest is "ab", xResults)	

	delete the first char of tTest
	testLog("Char", "DeleteFirstChar", tTest is "b", xResults)	
*/
end handler

public handler testFile(inout xResults as List)
	variable tData as Data
	put the contents of file "/dev/null" into tData
	testLog("File", "GetEmptyContents", tData is empty, xResults)
end handler

public handler testStream(inout xResults as List)

end handler

public handler testSystem(inout xResults as List)
	testLog("System", "OperatingSystemNonEmpty", the operating system is not empty, xResults)
end handler

public handler testDate(inout xResults as List)
    testLog("Date", "LocalDateListLength", the number of elements in the local date is 6, xResults)
    testLog("Date", "UniversalTimeIsAPositiveNumber", the universal time > 0, xResults)
end handler

end module
