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

WFURITest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2011 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 WFURI = require "WFURI"
local WFPlatformInfo = require "WFPlatformInfo"

--============================================================================--

local WFURITest = {}

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

function WFURITest.testResolve()

	local example = "http://a/b/c/d;p?q"
	
	local function test( s, answer, custom_example )
		local result = WFURI.resolve( custom_example or example, s )
		assert( answer == result, string.format( "result mismatched. expected: %s result: %s", answer, result ) )
	end
			
	test( "g:h", 	  "g:h" )
	test( "g",        "http://a/b/c/g" )
	test( "./g",      "http://a/b/c/g" )
	test( "g/",       "http://a/b/c/g/" )
	test( "g//h",     "http://a/b/c/g/h" )
	test( "/g",       "http://a/g" )
	test( "//g",      "http://g" )
	test( "?y",       "http://a/b/c/?y" )
	test( "g?y",      "http://a/b/c/g?y" )
	test( "g#s",      "http://a/b/c/g#s" )
	test( "g?y#s",    "http://a/b/c/g?y#s" )
	test( ";x",       "http://a/b/c/;x" )
	test( "g;x",      "http://a/b/c/g;x" )
	test( "g;x?y#s",  "http://a/b/c/g;x?y#s" )
	test( ".",        "http://a/b/c/" )
	test( "./",       "http://a/b/c/" )
	test( "..",       "http://a/b/" )
	test( "../",      "http://a/b/" )
	test( "../g",     "http://a/b/g" )
	test( "../..",    "http://a/" )
	test( "../../",   "http://a/" )
	test( "../../g",  "http://a/g" )
	test( "../../../../../g",  "http://a/g" )
	test( "#s",       "http://a/b/c/d;p?q#s" )
	test( "#s",       "http://a/b/c/d;p?q#s", "http://a/b/c/d;p?q#f" )
	test( ".",        "http://a/b/c/" )
	test( "g/h",      "http://a/g/h", "http://a/" )

	-- special edge case
	test( "", "" )
	test( ".", "", "" ) --Lr Bug #1302454
end

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

function WFURITest.testStringByAppendingPathComponents()

	local s = WFURI.stringByAppendingPathComponents
	assert( s( '/foo/bar', 'bah' ) == '/foo/bar/bah', 'stringByAppendingPathComponents' )
	assert( s( '/foo/bar/', 'bah' ) == '/foo/bar/bah', 'stringByAppendingPathComponents' )
	assert( s( '/foo/bar/', '/bah' ) == '/foo/bar/bah', 'stringByAppendingPathComponents' )
	assert( s( '/foo/bar', '/bah' ) == '/foo/bar/bah', 'stringByAppendingPathComponents' )
	assert( s( '/foo/bar', '' ) == '/foo/bar/', 'stringByAppendingPathComponents' )
	assert( s( '', 'foo/' ) == 'foo/', 'stringByAppendingPathComponents' )

end

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

function WFURITest.testStringByDeletingLastPathComponent()

	local d = WFURI.stringByDeletingLastPathComponent
	local t = function( input, path, file )
		local x, y = d( input )
		assert( x == path, 'stringByDeletingLastPathComponent_path ' .. input )
		assert( y == file, 'stringByDeletingLastPathComponent_file ' .. input )
		
	end
	t( '/foo/bar/bah/','/foo/bar', 'bah')
	t( '/foo/bar/bah','/foo/bar', 'bah' )
	t( '','', '' )
	t( '/','/', '' )
	t( 'foo','' ,'foo' )
	t( '/bah','/', 'bah' )
	-- special edge case
	assert( WFURI.stringByDeletingLastPathComponent( nil ) == nil , "Output should be nil when input path is nil" )
	
end

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

function WFURITest.testUnescape()
	
	local unescape = WFURI.unescape
	
	local t = function( input, output )
		local result = unescape( input )
		assert( result == output, 'WFURI.unescape, Input was ' .. input )
	end
	
	t( '/foo/u=p%2Bp','/foo/u=p+p' )
	t( '/foo/u=p%40p','/foo/u=p@p' )
	
end

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

function WFURITest.testEscape()
	
	local escape = WFURI.escape
	local sBasicAscii = [[ !""#$%&''()*+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~]]
	local t = function( context, input, output )
		local result = escape( input, context )
		assert( result == output, 'WFURI.escape, Input was ' .. input )
	end
	
	t( 'unreserved', '/foo/u=p+p', '%2Ffoo%2Fu%3Dp%2Bp' )
	t( 'unreserved', '/foo/u=p@p', '%2Ffoo%2Fu%3Dp%40p' )
	t( 'unreserved', '/foo/u=p?p', '%2Ffoo%2Fu%3Dp%3Fp' )
	t( 'unreserved', '/foo/u=;p', '%2Ffoo%2Fu%3D%3Bp' )
	t( 'unreserved', '/foo/u=p&p', '%2Ffoo%2Fu%3Dp%26p' )
	t( 'unreserved', sBasicAscii, '%20%21%22%22%23%24%25%26%27%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~' )
	
	t( 'path', '/foo/u=p!$&\'()*+,;=p', '/foo/u=p!$&\'()*+,;=p' )
	t( 'path', '/foo/u=p@p', '/foo/u=p@p' )
	t( 'path', '/foo/u=p?p', '/foo/u=p%3Fp' )
	t( 'path', '/foo/u=;p', '/foo/u=;p' )
	t( 'path', '/foo/u=p&p', '/foo/u=p&p' )
    t( 'path', '/foo/p-._~p', '/foo/p-._~p' )
	t( 'path', sBasicAscii, "%20!%22%22%23$%25&''()*+,-./0123456789%3A;%3C=%3E@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~" )

	t( nil, '/foo/u=p@p&x=y', '/foo/u=p@p&x=y' )
	
	t( 'query', 'foo=p!$&?\'()*+,;=p', 'foo=p!$&\?\'()*%2B,;=p' )
	t( 'query', '/foo/u=p@p', '/foo/u=p@p' )
	t( 'query', '/foo/u=p?p', '/foo/u=p?p' )
	t( 'query', '/foo/u=;p', '/foo/u=;p' )
	t( 'query', '/foo/u=p&p', '/foo/u=p&p' )
    t( 'query', '/foo/p-._~p', '/foo/p-._~p' )
	t( 'query', sBasicAscii, "%20!%22%22%23$%25&''()*%2B,-./0123456789:;%3C=%3E@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~" )
	
	t( 'query_key', 'foo=p!$&?\'()*+,;=p&x=y', 'foo%3Dp!$%26?\'()*%2B,;%3Dp%26x%3Dy' )
	t( 'query_key', sBasicAscii, "%20!%22%22%23$%25%26''()*%2B,-./0123456789:;%3C%3D%3E@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~" )
    t( 'query_key', '/foo/p-._~p', '/foo/p-._~p' )

	t( 'http_query_key', 'a b', 'a+b' )
	t( 'http_query_key', ",;:@/?$'\"\\", '%2C%3B%3A%40%2F%3F%24%27%22%5C' )
	t( 'http_query_key', 'lightroom;x-lightroom', 'lightroom%3Bx-lightroom' )
	
	local success = pcall( escape, "", "invalid" )
	assert( not success, "cover invalid context case" )
	
end

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

function WFURITest.testUriFromFilePath()
	
	local uriFromFilePath = WFURI.uriFromFilePath
	
	local t = function( input, output )
		local result = uriFromFilePath( input )
		assert( result == output, 'WFURI.uriFromFilePath, Input was ' .. input )
	end
	
	
	if WFPlatformInfo.isWindows then
		t( '\\foo\\bar', 'file:////foo/bar' )
		t( '\\', 'file:////' )
	else
		t( '/foo/bar', 'file:////foo/bar' )
		t( '/', 'file:////' )
	end

end

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

function WFURITest.testFilePathToURIPath()
	
	local filePathToURIPath = WFURI.filePathToURIPath
	
	local t = function( input, output )
		local result = filePathToURIPath( input )
		assert( result == output, 'WFURI.filePathToURIPath, Input was ' .. input .. " result was " .. result .. " expected " .. output )
	end
	
	t( '', '' )
	if not WFPlatformInfo.isWindows then
		t( '/foo/bar/', '/foo/bar/' )
		t( '/', '/' )
		t( '/file needing escaping \226\150\186/', '/file%20needing%20escaping%20%E2%96%BA/' )
	else
		t( '\\foo\\bar', '/foo/bar' )
		t( '\\', '/' )
		t( '\\file needing escaping \226\150\186\\', '/file%20needing%20escaping%20%E2%96%BA/' )
	end
end

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

local function fakeG( key, value, fn )
	
	local LOADED = debug.getregistry()[ "_LOADED" ]
	LOADED.WFURI = nil
	
	local orig = rawget( _G, key )

	rawset( _G, key, value )

	local results = { pcall( fn ) }

	rawset( _G, key, orig )
	LOADED.WFURI = nil

	if results[ 1 ] then
		return unpack( results, 2, #results )
	else
		error( unpack( results, 2, #results ) )
	end
	
end

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

local function fakeRequire( nameOfNamespace, fakeNamespace, fn )
	
	local LOADED = debug.getregistry()[ "_LOADED" ]
	LOADED.WFURI = nil
	
	local orig = LOADED[ nameOfNamespace ]
	LOADED[ nameOfNamespace ] = fakeNamespace

	local results = { pcall( fn ) }

	LOADED[ nameOfNamespace ] = orig
	LOADED.WFURI = nil

	if results[ 1 ] then
		return unpack( results, 2, #results )
	else
		error( unpack( results, 2, #results ) )
	end
	
end

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

function WFURITest.testUriPathToFilePath()
	
	local t = function( input, output )
		local uriPathToFilePath = require 'WFURI'.uriPathToFilePath
	
		local result = uriPathToFilePath( input )
		assert( result == output, 'WFURI.uriPathToFilePath, Input was ' .. input )
	end
	
	local nixTests = function()
		t( '/foo/bar/', '/foo/bar/' )
		t( '/', '/' )
	end
	local winTests = function()
		t( '/foo/bar/', '\\foo\\bar\\' )
		t( '/', '\\' )
	end

	-- Coerce platform checking to allow coverage of all our known platform branches

	fakeG( "MAC_ENV", true, nixTests )
	fakeG( "MAC_ENV", false, function()
		fakeG( "WIN_ENV", true, winTests )
		fakeRequire( "WFPlatformInfo", { isWindows = true }, function()
			fakeG( "WIN_ENV", false, winTests )
		end )
	end )
	
end


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

function WFURITest.testParse()
	
	local parsedURI = WFURI.parse( "http://server:8080/path/bin/file.asp?q=query#fragment1" )
	
	assert( type( parsedURI ) == 'table', "parsed result should be of table type" )

	assert( parsedURI.scheme == 'http', "Incorrect scheme" )
	
	assert( parsedURI.authority == "server:8080", "Incorrect authority" )
	
	assert( parsedURI.rawPath == "/path/bin/file.asp", "Wrong raw path" )
	
	assert( parsedURI.query == "q=query", "wrong query part" )
	
	assert( parsedURI.fragment == "fragment1", "wrong fragment" )
	
end

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

function WFURITest.testParseQueryString()

	local parsedURI = WFURI.parse( "http://server:8080/path/bin/file.asp?q=query#fragment1" )

	local params = WFURI.parseQueryString( parsedURI.query )
	
	assert( params.q == "query", "Wrong query param" )
	
	params.q = nil
	
	assert( next( params ) == nil, "Unexpected query param" )
	
	params = WFURI.parseQueryString( "k=v&k=v" )
	
	assert( params.k == 'v', "duplicate keys" )

end

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

function WFURITest.testBuildQueryString()
	local buildQueryString = assert( WFURI.buildQueryString, "Fn is in namespace" )
	assert( buildQueryString { ["a b"] = "c+d" } == "a+b=c%2Bd" )
	assert( buildQueryString { aps_env = "foo", aps_id = "bar" } == "aps_env=foo&aps_id=bar" )
	assert( buildQueryString { [ "a=b" ] = "c&d" } == "a%3Db=c%26d" )
	assert( buildQueryString { } == "" )
	assert( buildQueryString( { aps_env = "foo", aps_id = "bar" }, false ) == "aps_env=foo&aps_id=bar" )
end

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

function WFURITest.testSanitizedString()

    local url = "https://example.com/path/here?query#fragment"
	
	local sanitize = WFURI.sanitizedString
	
	assert( type( sanitize ) == 'function', "WFURI namespace has sanitizedString function" )
	
	assert( sanitize( url ) == url )

	url = "https://example.com:8080/path/here?query#fragment"
	assert( sanitize( url ) == url )

 	url = "https://bob@example.com/path/here?query#fragment"
	assert( sanitize( url ) == url )

 	url = "https://bob:foo@example.com/path/here?query#fragment"
	assert( sanitize( url ) == "https://bob:*****@example.com/path/here?query#fragment" )

 	url = "/foo/bar/baz?a:sdf#foo:bar"
	assert( sanitize( url ) == url )

end

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

function WFURITest.testBuildUri()
	
	local build = WFURI.buildUri
	
	local params = WFURI.parse 'http://foo.bar.com/some+path'

	assert( build( params ) == 'http://foo.bar.com/some+path' )
		-- test with both path and rawPath
	
	local path = params.path
	params.path = nil
	
	assert( build( params ) == 'http://foo.bar.com/some+path' )
		-- test with only rawPath

	params.path = path
	params.rawPath = nil
	
	assert( build( params ) == 'http://foo.bar.com/some+path' )
		-- test with only path
	
	params.query = "x=12&y=_"
	assert( build( params ) == 'http://foo.bar.com/some+path?x=12&y=_' )

	params.fragment = "anchor"
	assert( build( params ) == 'http://foo.bar.com/some+path?x=12&y=_#anchor' )

	params.query = nil
	assert( build( params ) == 'http://foo.bar.com/some+path#anchor' )
	
end

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

function WFURITest.testIsEqual()
	
	local isEqual = assert( WFURI.isEqual, "has fn" )
	
	assert( isEqual( "a://b/c?d#e", "a://b/c?d#e" ), "simple" )
	
	assert( isEqual( "a://%62/%63?%64#%65", "a://b/c?d#e" ), "Percent-encoding normalization" )
	
	assert( isEqual( "a://%6a/%6b?%6c#%6d", "a://%6A/%6B?%6C#%6D" ), "Case Normalization" )
	
	assert( isEqual( "a://b/c/f/g?d#e", "a://b/c/h/../f/./g?d#e" ), "Path Segment Normalization" )
	
	assert( not isEqual( "a://b//c/f/g?d#e", "a://b/c/h/../f/./g?d#e" ), "Double leading slash survives Path Segment Normalization" )
	
	assert( not isEqual( "f://b/c?d#e", "a://b/c?d#e" ), "different scheme" )
	assert( not isEqual( "a://f/c?d#e", "a://b/c?d#e" ), "different authority" )
	assert( not isEqual( "a://b/f?d#e", "a://b/c?d#e" ), "different path" )
	assert( not isEqual( "a://b/c?f#e", "a://b/c?d#e" ), "different query" )
	assert( not isEqual( "a://b/c?d#f", "a://b/c?d#e" ), "different fragment" )

	assert( not isEqual( "a://b/c?", "a://b/c" ), "empty query vs no query" )
	assert( not isEqual( "a://b/c?#", "a://b/c?" ), "empty fragment vs no fragment" )
	
end

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

function WFURITest.testOzV2Patterns()

	local function validateUrl( base, s, expected )
	
		local final = WFURI.resolve( base, s )
		
		assert( final == expected, 'Different URI' )
		
	end
	
	local base = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/'
	local url = '/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	local expected = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	
	validateUrl( base, url, expected )
	
	base = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/'
	url = 'assets/415ad20263524dc786c1273c02ba5efc'
	expected = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	
	validateUrl( base, url, expected )
	
	base = 'https://photos.adobe.io/'
	url = '/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	expected = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	
	validateUrl( base, url, expected )
	
	base = 'https://photos-download.adobe.io'
	url = '/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	expected = 'https://photos-download.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	
	validateUrl( base, url, expected )
	
	base = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/'
	url = 'https://photos.adobe-static.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	expected = 'https://photos.adobe-static.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	
	validateUrl( base, url, expected )
	
	base = 'https://photos.adobe.io/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/'
	url = 'assets/415ad20263524dc786c1273c02ba5efc'
	expected = '/v2/catalogs/6ad4dd0e42654ae8a09d4f435274c491/assets/415ad20263524dc786c1273c02ba5efc'
	
	local absoluteUrl = WFURI.resolve( base, url )
	
	local urlTable = WFURI.parse( absoluteUrl )
	
	assert( urlTable.path == expected, 'Expected absolute path' )
	
end

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

function WFURITest.testReplaceFromOzTemplate()
	local testTemplate = "{verb} {subject}!"

	local templateFull, populatedTemplate = WFURI.replaceFromOzTemplate(testTemplate, {
		verb    = "Hello",
	})

	assert( templateFull == false, "Template is not fully populated")
	assert( populatedTemplate == "Hello {subject}!", "Template has hole")

	templateFull, populatedTemplate = WFURI.replaceFromOzTemplate(testTemplate, {
		verb    = "Hello",
		subject = "World",
	})

	assert( templateFull == true, "Template is fully populated" )
	assert( populatedTemplate == "Hello World!", "Template has no hole")
end

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

return WFURITest
