--[[----------------------------------------------------------------------------

KSStringUtilsTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2012 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

------------------------------------------------------------------------------]]

local KSStringUtilsTest = {}

--------------------------------------------------------------------------------

local KSStringUtils = require 'KSStringUtils'

local WFPlatformInfo = require 'WFPlatformInfo'

--------------------------------------------------------------------------------

function KSStringUtilsTest.testi18n_collate()
	
	assert( KSStringUtils.localizedStringCompare( "Abc", "Def" ) < 0, "'Abc' not < 'Def'" )
	assert( KSStringUtils.localizedStringCompare( "Abc", "Abc" ) == 0, "'Abc' != 'Abc'" )
	assert( KSStringUtils.localizedStringCompare( "Def", "Abc" ) > 0, "'Def' not > 'Abc'" )
	
	assert( KSStringUtils.localizedStringCompare( "A", "N" ) < 0, "1: 'A' not < 'N'" )
	assert( KSStringUtils.localizedStringCompare( "N", "n" ) < 0, "2: 'N' not < 'n'" )
	assert( KSStringUtils.localizedStringCompare( "n", "N1" ) < 0, "3: 'n' not < 'N1'" )
	assert( KSStringUtils.localizedStringCompare( "N1", "n1" ) < 0, "4: 'N1' not < 'n1'" )
	assert( KSStringUtils.localizedStringCompare( "n1", "N2" ) < 0, "5: 'n1' not < 'N2'" )
	assert( KSStringUtils.localizedStringCompare( "N2", "n2" ) < 0, "6: 'N2' not < 'n2'" )
		
	if not WFPlatformInfo.isAndroid and not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStringCompare( "n2", "N10" ) < 0, "7: 'n2' not < 'N10'" )
	end
		
	assert( KSStringUtils.localizedStringCompare( "N10", "n10" ) < 0, "8: 'N10' not < 'n10'" )
	assert( KSStringUtils.localizedStringCompare( "n10", "\195\145" ) < 0, "9: 'n10' not < '\195\145'" )
	assert( KSStringUtils.localizedStringCompare( "\195\145", "\195\1451" ) < 0, "10: '\195\145' not < '\195\1451'" )
	assert( KSStringUtils.localizedStringCompare( "\195\1451", "\195\1452" ) < 0, "11: '\195\1451' not < '\195\1452'" )
		
	if not WFPlatformInfo.isAndroid and not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStringCompare( "\195\1452", "\195\14510" ) < 0, "12: '\195\1452' not < '\195\14510'" )
		assert( KSStringUtils.localizedStringCompare( "\195\14510", "Z" ) < 0, "13: '\195\14510' not < 'Z'" )
	end
	
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testi18n_localized_standard_compare()
	
	assert( KSStringUtils.localizedStandardStringCompare( "Abc", "Def" ) < 0, "'Abc' not < 'Def'" )
	assert( KSStringUtils.localizedStandardStringCompare( "Abc", "Abc" ) == 0, "'Abc' != 'Abc'" )
	assert( KSStringUtils.localizedStandardStringCompare( "Def", "Abc" ) > 0, "'Def' not > 'Abc'" )

	assert( KSStringUtils.localizedStandardStringCompare( "A", "n" ) < 0, "1: 'A' not < 'n'" )
	
	-- FIXME_WIN32:  This exception can be eliminated if the parameters are reversed for the case sensitive compare (see Android).
	if not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "n", "N" ) < 0, "2: 'n' not < 'N'" )
	end
	
	assert( KSStringUtils.localizedStandardStringCompare( "N", "\195\145" ) < 0, "3: 'N' not < '\195\145'" )

	if not WFPlatformInfo.isAndroid and not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "\195\145", "n1" ) < 0, "4: '\195\145' not < 'n1'" )
	end

	-- FIXME_WIN32:  This exception can be eliminated if the parameters are reversed for the case sensitive compare (see Android).
	if not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "n1", "N1" ) < 0, "5: 'n1' not < 'N1'" )
	end

	assert( KSStringUtils.localizedStandardStringCompare( "N1", "\195\1451" ) < 0, "6: 'N1' not < '\195\1451'" )

	if not WFPlatformInfo.isAndroid and not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "\195\1451", "n2" ) < 0, "7: '\195\1451' not < 'n2'" )
	end

	-- FIXME_WIN32:  This exception can be eliminated if the parameters are reversed for the case sensitive compare (see Android).
	if not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "n2", "N2" ) < 0, "8: 'n2' not < 'N2'" )
	end

	assert( KSStringUtils.localizedStandardStringCompare( "N2", "\195\1452" ) < 0, "9: 'N2' not < '\195\1452'" )

	if not WFPlatformInfo.isAndroid and not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "\195\1452", "n10" ) < 0, "10: '\195\1452' not < 'n10'" )
	end

	-- FIXME_WIN32:  This exception can be eliminated if the parameters are reversed for the case sensitive compare (see Android).
	if not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "n10", "N10" ) < 0, "11: 'n10' not < 'N10'" )
	end

	assert( KSStringUtils.localizedStandardStringCompare( "N10", "\195\14510" ) < 0, "12: 'N10' not < '\195\14510'" )

	if not WFPlatformInfo.isAndroid and not WFPlatformInfo.isWindows then
		assert( KSStringUtils.localizedStandardStringCompare( "\195\14510", "Z" ) < 0, "13: '\195\14510' not < 'Z'" )
	end
	
end

--------------------------------------------------------------------------------

local kUpperADoubleDot = "\195\132"
local kLowerADoubleDot = "\195\164"


function KSStringUtilsTest.testLower()
	
	local function t( input, expected )
		local result = KSStringUtils.lower( input )
		local success = result == expected
		if not success then
			assert( success, "'" .. input .. "' not lowered" )
		end
	end
	
	t( "ABC", 'abc' )
	t( "AbC", 'abc' )
	t( "  AbC  ", '  abc  ' )
	t( "", '' )
	
	t( kUpperADoubleDot, kLowerADoubleDot )
	t( kLowerADoubleDot, kLowerADoubleDot )

end

--------------------------------------------------------------------------------


function KSStringUtilsTest.testUpper()

	local function t( input, expected )
		local result = KSStringUtils.upper( input )
		local success = result == expected
		if not success then
			assert( success, "'" .. input .. "' not lowered" )
		end
	end
	
	t( "ABC", 'ABC' )
	t( "AbC", 'ABC' )
	t( "  AbC  ", '  ABC  ' )
	
	t( kUpperADoubleDot, kUpperADoubleDot )
	t( kLowerADoubleDot, kUpperADoubleDot )

end

--------------------------------------------------------------------------------


function KSStringUtilsTest.testTrim()

	assert( KSStringUtils.trim( "ABC" ) == 'ABC', "'ABC' not trimmed" )
	assert( KSStringUtils.trim( "  AbC" ) == 'AbC', "'  AbC' not trimmed" )
	assert( KSStringUtils.trim( "AbC  " ) == 'AbC', "'AbC  ' not trimmed" )
	assert( KSStringUtils.trim( "   AbC  " ) == 'AbC', "'   AbC  ' not trimmed" )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testBase64()

	local KSData = require "KSData"
	
	local input = KSData.make( "Revel\n" )
	local encoded = KSStringUtils.encodeBase64( input )
	assert( encoded == 'UmV2ZWwK', "'Revel' not base64 encoded" )
	
	input = "V2ljaGl0YSBGb3VuZGF0aW9uCg=="
	local decodedString = KSStringUtils.decodeBase64AsString( input )
	assert( decodedString == 'Wichita Foundation\n', "'Wichita Foundation' not base64 decoded" )
	local decoded = KSStringUtils.decodeBase64( input )
	local shaSum = decoded:digest( "SHA1" )
	assert( shaSum == '2ab9cb1ad8ad25cd2ba1448da3cb705b44a44c84', "'Revel' not base64 decoded" )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testEscapeHtml()

	local str = [[
	<html lang="en">
		<head>Test</head>
		<body>Just a small html example with an ampersand (&) in it.</body>
	</html>
	]]

	local escapedHtmlStr = KSStringUtils.escapeHtml(str)

	local expectedStr = [[
	&lt;html lang=&quot;en&quot;&gt;
		&lt;head&gt;Test&lt;/head&gt;
		&lt;body&gt;Just a small html example with an ampersand (&amp;) in it.&lt;/body&gt;
	&lt;/html&gt;
	]]
	
	assert( escapedHtmlStr == expectedStr )
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testGetBaseContentType()

	assert( KSStringUtils.getBaseContentType( "image/jpeg" ) == "image/jpeg", "no property" )
	assert( KSStringUtils.getBaseContentType( "image/jpeg;key=value" ) == "image/jpeg", "one property" )
	assert( KSStringUtils.getBaseContentType( "image/jpeg;key=value;key2=value2" ) == "image/jpeg", "two properties" )
	
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testSplit()

	local a = KSStringUtils.split( "hello,world", "," )
	assert( a[ 1 ] == 'hello' )
	assert( a[ 2 ] == 'world' )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testConvertToHex()

	local KSData = require "KSData"
	
	local input = KSData.make( "TestKSData" )
	local hexOutput = KSStringUtils.convertToHex( input )
	assert( hexOutput == '546573744b5344617461', "'TestKSData' not converted to hex." )
	
	input = "TestStringData"
	local stringHexOutput = KSStringUtils.convertToHex( input )
	assert( stringHexOutput == '54657374537472696e6744617461', "'TestStringData' not converted to hex." )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testByteString()

	local bs = assert( KSStringUtils.byteString, 'fn' )
	
	assert( bs( 123456 ) == '120.56 KB', '123456' )
	assert( bs "a string" == "a string", "a string" )
	assert( bs {} == '', 'not string nor number' )
	assert( bs( 0/0 ) == '', 'nan' )
	assert( bs( -0.9 ) == '0 bytes', 'nonint' )
	assert( bs( -5 ) == '-5 bytes', 'nonint' )
	assert( bs( 1 ) == '1 byte', 'nonint' )
	
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testStorageByteString()

	local bs = assert( KSStringUtils.storageByteString, 'fn' )
	
	if WFPlatformInfo.isCocoa then
	
		assert( bs( -0.9 ) == '-0.90 bytes', 'nonint' )
		assert( bs( -5 ) == '-5 bytes', 'nonint' )
		assert( bs( 1 ) == '1 byte', 'nonint' )
		assert( bs( 100 ) == '100 bytes', '100' )
		assert( bs( 1000 ) == '1 KB', 'KB' )
		assert( bs( 1100 ) == '1.10 KB', 'KB' )
		assert( bs( 1100 * 1000 ) == '1.10 MB', 'MB' )
		assert( bs( 1100 * 1000  * 1000 ) == '1.10 GB', 'GB' )
		assert( bs( 1100 * 1000 * 1000 * 1000 ) == '1.10 TB', 'TB' )
		assert( bs( 1100 * 1000 * 1000 * 1000 * 1000 ) == '1.10 PB', 'PB' )
		
	else
	
		assert( bs( -0.9 ) == '-0.90 bytes', 'nonint' )
		assert( bs( -5 ) == '-5 bytes', 'nonint' )
		assert( bs( 1 ) == '1 byte', 'nonint' )
		assert( bs( 100 ) == '100 bytes', 'bytes' )
		assert( bs( 1000 ) == '1000 bytes', 'bytes' )
		assert( bs( 1024 ) == '1 KB', 'KB' )
		assert( bs( 1100 ) == '1.07 KB', 'KB' )
		assert( bs( 1100 * 1024 ) == '1.07 MB', 'MB' )
		assert( bs( 1100 * 1024  * 1024 ) == '1.07 GB', 'GB' )
		assert( bs( 1100 * 1024 * 1024 * 1024 ) == '1.07 TB', 'TB' )
		assert( bs( 1100 * 1024 * 1024 * 1024 * 1024 ) == '1.07 PB', 'PB' )
	
	end
	
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testTrimWhitespace()

	local t = assert( KSStringUtils.trimWhitespace, 'KSSU.tW' )

	assert( t 'hello' == 'hello', 'no ws' )
	assert( t ' hello' == 'hello', 'leading ws' )
	assert( t 'hello ' == 'hello', 'trailing ws' )
	assert( t 'hel lo' == 'hel lo', 'internal ws' )
	assert( t ' hel lo ' == 'hel lo', 'l/t/i ws' )
	assert( t '' == '', 'empty' )
	assert( t '\009\010\011\012\013\014X\008' == '\014X\008', 'ws control chars' )
	assert( t(
			'\226\128\128'
			.. '\226\128\129'
			.. '\226\128\130'
			.. '\226\128\131'
			.. '\226\128\132'
			.. '\226\128\133'
			.. '\226\128\134'
			.. '\226\128\135'
			.. '\226\128\136'
			.. '\226\128\137'
			.. '\226\128\138'
			.. '\226\128\139'
			.. 'X'
			.. '\225\191\191'
		) == (
			'\226\128\139'
			.. 'X'
			.. '\225\191\191'
		) , 'ws control chars' )
	assert( t '    ' == '', 'all ws' )
	assert( t '\078NO-BREAK SPACE\078', 'NO-BREAK SPACE', 'UTF-8 0x78' )
	assert( t '\227\128\128IDEOGRAPHIC SPACE\227\128\128', 'IDEOGRAPHIC SPACE', 'UTF-8 0xE38080' )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testMakeUTF8Processor()

	local m = assert( KSStringUtils.makeUTF8Processor, 'KSSU.mUTF8P' )
	
	local noExtraArgs = true
	local lastCharProcessed, lastCharUnicode
	local nCharsProcessed = 0
	
	local charProcessor = function( strChr, unicode, ... )
		noExtraArgs = noExtraArgs and select( '#', ... ) == 0
		lastCharProcessed = strChr
		lastCharUnicode = unicode
		nCharsProcessed = nCharsProcessed + 1
	end
	
	local lastMultiByteProcessed
	local nMultiBytesProcessed = 0
	
	local multiByteProcessor = function( unicode, ... )
		noExtraArgs = noExtraArgs and select( '#', ... ) == 0
		lastMultiByteProcessed = unicode
		nMultiBytesProcessed = nMultiBytesProcessed + 1
		return string.format( "{%08x}", unicode )
	end
	
	local p = assert( m( charProcessor, multiByteProcessor ), 'make processor' )
	
	assert( select( '#', p( 'x' ) ) == 0, 'processor returns none' )
	
	assert( nCharsProcessed == 1, 'nCP 1' )
	assert( lastCharProcessed == 'x', 'lCP 1' )
	assert( lastCharUnicode == 120, 'lCU 1' )
	assert( nMultiBytesProcessed == 0, 'nMBP 1' )

	assert( select( '#', p( '\232' ) ) == 0, 'processor returns none' )
	assert( select( '#', p( '\143' ) ) == 0, 'processor returns none' )
	assert( select( '#', p( '\176' ) ) == 0, 'processor returns none' )
	
	assert( nCharsProcessed == 2, 'nCP 2' )
	assert( lastCharProcessed == '{000083f0}', 'lCP 2' )
	assert( lastCharUnicode == 0x83F0, 'lCU 2' )
	assert( nMultiBytesProcessed == 1, 'nMBP 2' )
	assert( lastMultiByteProcessed == 0x83F0, 'lMBP 2' )

	assert( noExtraArgs, 'no extra args' )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testNumberToString()

	local f = assert( KSStringUtils.numberToString, 'KSSUT.nTS' )

	assert( f( 1001.2002, 5 ) == '1001.20020', '1001.2002 5' )
	assert( f( 1001.2002, 4 ) == '1001.2002', '1001.2002 4' )
	assert( f( 1001.2002, 3 ) == '1001.200', '1001.2002 3' )
	assert( f( 1001.2006, 3 ) == '1001.201', '1001.2006 3' )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testSystemInternationalString()

	local si = assert( KSStringUtils.systemInternationalString, 'KSSUT.sIS' )

	assert( si( 0, 'm' ) == '0 m', '0 m' )
	assert( si( 999, 'm', 2 ) == '999 m', '999 m' )
	assert( si( -1000, 'm', 2 ) == '-1 km', '1000 m' )
	assert( si( 9876, 'm', 3 ) == '9.876 km', '9876 m' )
	assert( si( 1000000000000000000000, 'B', 3 ) == '1000 EB', '1 ZB' )
	assert( si( 'a string' ) == 'a string', 'invalid type' )
	
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testFormattedFraction()

	local ff = assert( KSStringUtils.formattedFraction, 'KSSUT.fF' )

	assert( ff( "wrong type" ), "?", 'invalid entry' )

	assert( ff( 8, 1, false ), "8", '8/1 U' )
	assert( ff( 41, -1, false ), "-41", '-41/1 U' )
	assert( ff( 10, 9, false ), "1 \226\129\176\226\129\132\226\130\137", '10/9 U' )
	assert( ff( 1, 5, false ), "\226\133\149", '1/5 U' )
	assert( ff( -1, 5, false ), "\226\128\146 \226\133\149", '-1/5 U' )

	assert( ff( 6, 10, true ), "3/5", '6/10 A' )
	assert( ff( 6.2, -10, true ), "3/5", '6.2/10 A' )
	assert( ff( -12, 10, true ), "1 1/5", '-12/10 A' )
	assert( ff( -20, -10, true ), "2", '20/10 A' )
	assert( ff( 0, 10, true ), "0", '0/10 A' )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testValidateUTF8()

	local validate = assert( KSStringUtils.validateUTF8, 'KSSUT.validateUTF8' )

	assert( validate( "Should Be Valid" ), "?", 'invalid entry' )
	
	local appName = WFPlatformInfo.getAppName()
	
	assert( validate( appName ), "?", 'invalid entry' )
	
	local maybeUtf16Str = KSStringUtils.getUTF16String_DEBUG()
	
	if maybeUtf16Str then
		assert( not validate( maybeUtf16Str ), "?", 'false positive' )
	end
	
end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testLengthOfUTF8String()

	local ascii = "1234"
	assert( KSStringUtils.lengthOfUTF8String( ascii ) == 4 )

	local doubleByteChar = '\195\165'
	local threeDoubleByte = doubleByteChar .. doubleByteChar .. doubleByteChar
	assert( KSStringUtils.lengthOfUTF8String( threeDoubleByte ) == 3 )

	local japaneseseChar = '\229\137\141'
	assert( KSStringUtils.lengthOfUTF8String( japaneseseChar ) == 1 )
	
	local asciiChar = "9"
	local mixed = asciiChar .. japaneseseChar .. asciiChar .. doubleByteChar .. asciiChar
	assert( KSStringUtils.lengthOfUTF8String( mixed ) == 5 )

end

--------------------------------------------------------------------------------

function KSStringUtilsTest.testUTF8Substring()

	local ascii = "1234"
	assert( KSStringUtils.UTF8Substring( ascii, 0, 1 ) == "1" )
	assert( KSStringUtils.UTF8Substring( ascii, 1, 2 ) == "12" )
	assert( KSStringUtils.UTF8Substring( ascii, 1, 4 ) == "1234" )
	assert( KSStringUtils.UTF8Substring( ascii, 4, 4 ) == "4" )
	assert( KSStringUtils.UTF8Substring( ascii, 3 ) == "34" )
	
	local doubleByteChar = '\195\165'
	local threeDoubleByte = doubleByteChar .. doubleByteChar .. doubleByteChar
	assert( KSStringUtils.UTF8Substring( threeDoubleByte, 1, 1 ) == doubleByteChar )
	assert( KSStringUtils.UTF8Substring( threeDoubleByte, 1, 3 ) == threeDoubleByte )
	assert( KSStringUtils.UTF8Substring( threeDoubleByte, 3, 3 ) == doubleByteChar )

	local japaneseseChar = '\229\137\141'
	local asciiChar = "9"
	local mixed = asciiChar .. japaneseseChar .. asciiChar .. doubleByteChar .. asciiChar
	assert( KSStringUtils.UTF8Substring( mixed, 1, 1 ) == asciiChar )
	assert( KSStringUtils.UTF8Substring( mixed, 1, 3 ) == asciiChar .. japaneseseChar .. asciiChar )
	assert( KSStringUtils.UTF8Substring( mixed, 1, 5 ) == mixed )
	assert( KSStringUtils.UTF8Substring( mixed, 4, 5 ) == doubleByteChar .. asciiChar )

end

--------------------------------------------------------------------------------

return KSStringUtilsTest
