<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script>

function testIDNEncode(charCode)
{
    var str = String.fromCharCode(charCode);
    str = testRunner.encodeHostName(str);
    if (str.substr(0, 4) == "xn--")
        return "punycode";
    return escape(str);
}

function testIDNEncodeNotFirstCharacter(charCode)
{
    var str = String.fromCharCode(charCode);
    str = "a" + str;
    str = testRunner.encodeHostName(str);
    if (str.substr(0, 4) == "xn--")
        return "punycode";
    if (str.substr(0, 1) == "a")
        str = str.substr(1, str.length - 1);
    return escape(str);
}

function testIDNRoundTrip(charCode)
{
    var str = String.fromCharCode(charCode);
    str = testRunner.encodeHostName(str);
    str = testRunner.decodeHostName(str);
    if (str.substr(0, 4) == "xn--")
        return "punycode";
    return escape(str);
}

function testIDNRoundTripNotFirstCharacter(charCode)
{
    var str = String.fromCharCode(charCode);
    str = "a" + str;
    str = testRunner.encodeHostName(str);
    str = testRunner.decodeHostName(str);
    if (str.substr(0, 4) == "xn--")
        return "punycode";
    if (str.substr(0, 1) == "a")
        str = str.substr(1, str.length - 1);
    return escape(str);
}

function testFunctionName(expected)
{
    if (expected == "does not encode")
        return "testIDNEncode";
    return "testIDNRoundTrip";
}

function expectedTestResult(charCode, expected)
{
    if (expected == "disallowed")
        return "'punycode'";
    if (expected == "allowed" || expected == "does not encode")
        return "'" + escape(String.fromCharCode(charCode)) + "'";
    return "'" + expected + "'";
}

function testIDNCharacter(charCode, expected, expectedNotFirstCharacter)
{
    if (expectedNotFirstCharacter == null)
        expectedNotFirstCharacter = expected;

    shouldBe(testFunctionName(expected) + "(0x" + charCode.toString(16) + ")",
        expectedTestResult(charCode, expected));

    shouldBe(testFunctionName(expectedNotFirstCharacter) + "NotFirstCharacter(0x" + charCode.toString(16) + ")",
        expectedTestResult(charCode, expectedNotFirstCharacter));    
}

function testBecomesSpaceIDNCharacter(charCode)
{
    shouldBe("testIDNRoundTrip(0x" + charCode.toString(16) + ")", "'%20'");
    shouldBe("testIDNRoundTripFirstCharacter(0x" + charCode.toString(16) + ")", "'%20'");
}

function testBecomesASCIIIDNCharacter(charCode, expected)
{
    shouldBe("testIDNRoundTrip(0x" + charCode.toString(16) + ")", "'" + expected + "'");
    shouldBe("testIDNRoundTripFirstCharacter(0x" + charCode.toString(16) + ")", "'" + expected + "'");
}

function testDisallowedIDNCharacter(charCode)
{
    shouldBe("testIDNRoundTrip(0x" + charCode.toString(16) + ")", "'punycode'");
    shouldBe("testIDNRoundTripFirstCharacter(0x" + charCode.toString(16) + ")", "'punycode'");
}

function testAllowedIDNCharacter(charCode)
{
    var expected = escape(String.fromCharCode(charCode));
    shouldBe("testIDNRoundTrip(0x" + charCode.toString(16) + ")", "'" + expected + "'");
    shouldBe("testIDNRoundTripFirstCharacter(0x" + charCode.toString(16) + ")", "'" + expected + "'");
}

function testDoesNotEncodeIDNCharacter(charCode)
{
    var expected = escape(String.fromCharCode(charCode));
    shouldBe("testIDNEncode(0x" + charCode.toString(16) + ")", "'" + expected + "'");
    shouldBe("testIDNEncodeTripFirstCharacter(0x" + charCode.toString(16) + ")", "'" + expected + "'");
}

var isOlderICU = testIDNEncode(0x3002) == ".";

/* Allowed Characters - dot and slash */
testIDNCharacter(".".charCodeAt(0), "allowed");
testIDNCharacter("/".charCodeAt(0), "allowed");

/* Allowed Characters - one character for each script in the default IDN allowlist*/
testIDNCharacter(0x0061, "allowed");
testIDNCharacter(0x0633, "allowed");
testIDNCharacter(0x0561, "allowed");
testIDNCharacter(0x3105, "allowed");
testIDNCharacter(0x1613, "allowed");
testIDNCharacter(0x0905, "allowed");
testIDNCharacter(0x0A85, "allowed");
testIDNCharacter(0x0A05, "allowed");
testIDNCharacter(0x1115, "allowed");
testIDNCharacter(0x4E2D, "allowed");
testIDNCharacter(0x05D0, "allowed");
testIDNCharacter(0x3041, "allowed");
testIDNCharacter(0x30A1, "allowed");
testIDNCharacter(0x0B94, "allowed");
testIDNCharacter(0x0E02, "allowed");
testIDNCharacter(0xA000, "allowed");

/* ICU converts these to other allowed characters, so the original character can't be used to get to a phishy domain name */
testIDNCharacter(0xFF0F, "/");

/* ICU converts these characters to backslash, so the original character can't be used to get to a phishy domain name */
testIDNCharacter(0xFE68, "%5C");
testIDNCharacter(0xFF3C, "%5C");

/* ICU converts these characters to space, so the original character can't be used to get to a phishy domain name */
testIDNCharacter(0x00A0, "%20");
testIDNCharacter(0x2000, "%20");
testIDNCharacter(0x2001, "%20");
testIDNCharacter(0x2002, "%20");
testIDNCharacter(0x2003, "%20");
testIDNCharacter(0x2004, "%20");
testIDNCharacter(0x2005, "%20");
testIDNCharacter(0x2006, "%20");
testIDNCharacter(0x2007, "%20");
testIDNCharacter(0x2008, "%20");
testIDNCharacter(0x2009, "%20");
testIDNCharacter(0x200A, "%20");
testIDNCharacter(0x202F, "%20");
testIDNCharacter(0x205F, "%20");
testIDNCharacter(0x3000, "%20");

/* Disallow these characters.  Some of these are known lookalike characters for dot and slash.  
   A lot of these are from Mozilla's blocklist: http://kb.mozillazine.org/Network.IDN.blacklist_chars
*/
testIDNCharacter(0x00BC, "disallowed");
testIDNCharacter(0x00BD, "disallowed");
testIDNCharacter(0x00ED, "allowed");
testIDNCharacter(0x01C3, "disallowed");
testIDNCharacter(0x0251, "disallowed");
testIDNCharacter(0x0261, "disallowed");
testIDNCharacter(0x2027, "disallowed");
testIDNCharacter(0x2039, "disallowed");
testIDNCharacter(0x203A, "disallowed");
testIDNCharacter(0x2044, "disallowed");
testIDNCharacter(0x2044, "disallowed");
testIDNCharacter(0x2154, "disallowed");
testIDNCharacter(0x2155, "disallowed");
testIDNCharacter(0x2156, "disallowed");
testIDNCharacter(0x2159, "disallowed");
testIDNCharacter(0x215A, "disallowed");
testIDNCharacter(0x215B, "disallowed");
testIDNCharacter(0x215F, "disallowed");
testIDNCharacter(0x2215, "disallowed");
testIDNCharacter(0x2216, "disallowed");
testIDNCharacter(0x233F, "disallowed");
testIDNCharacter(0x23AE, "disallowed");
testIDNCharacter(0x244A, "disallowed");
testIDNCharacter(0x2571, "disallowed");
testIDNCharacter(0x2572, "disallowed");
testIDNCharacter(0x29F6, "disallowed");
testIDNCharacter(0x29F8, "disallowed");
testIDNCharacter(0x29F8, "disallowed");
testIDNCharacter(0x2AFB, "disallowed");
testIDNCharacter(0x2AFD, "disallowed");
testIDNCharacter(0x3014, "disallowed");
testIDNCharacter(0x3015, "disallowed");
testIDNCharacter(0x3033, "disallowed");
testIDNCharacter(0x3035, "disallowed");
testIDNCharacter(0x33AE, "disallowed");
testIDNCharacter(0x33AF, "disallowed");
testIDNCharacter(0x33C6, "disallowed");
testIDNCharacter(0x33DF, "disallowed");
testIDNCharacter(0xFE3F, "disallowed");
testIDNCharacter(0xFE5D, "disallowed");
testIDNCharacter(0xFE5E, "disallowed");

/* ICU won't encode these characters in IDN, thus we should always get 'host not found'. */
testIDNCharacter(0x2028, "does not encode");
testIDNCharacter(0x2029, "does not encode");
testIDNCharacter(0x2FF0, "does not encode");
testIDNCharacter(0x2FF1, "does not encode");
testIDNCharacter(0x2FF2, "does not encode");
testIDNCharacter(0x2FF3, "does not encode");
testIDNCharacter(0x2FF4, "does not encode");
testIDNCharacter(0x2FF5, "does not encode");
testIDNCharacter(0x2FF6, "does not encode");
testIDNCharacter(0x2FF7, "does not encode");
testIDNCharacter(0x2FF8, "does not encode");
testIDNCharacter(0x2FF9, "does not encode");
testIDNCharacter(0x2FFA, "does not encode");
testIDNCharacter(0x2FFB, "does not encode");
testIDNCharacter(0xFFF9, "does not encode");
testIDNCharacter(0xFFFA, "does not encode");
testIDNCharacter(0xFFFB, "does not encode");
testIDNCharacter(0xFFFC, "does not encode");
testIDNCharacter(0xFFFD, "does not encode");

/* ICU won't encode these characters if they're not the first character in the host name.  
   If the character does get encoded as the first character, then we will disallow it */
   
testIDNCharacter(0x05C3, "disallowed", "does not encode");
testIDNCharacter(0x05F4, "disallowed", "does not encode");
testIDNCharacter(0x06D4, "disallowed", "does not encode");
testIDNCharacter(0x0702, "disallowed", "does not encode");

/* ICU won't encode these characters if they're the first character in the host name.  
   If the character does get encoded as the first character, then ICU converts it to another allowed character */

if (isOlderICU) {
    testIDNCharacter(0x200B, "");
    testIDNCharacter(0x3002, ".");
    testIDNCharacter(0xFF0E, ".");
    testIDNCharacter(0xFF61, ".");
    testIDNCharacter(0xFEFF, "");
    testIDNCharacter(0x2024, ".");
    testIDNCharacter(0xFE52, ".");
    testIDNCharacter(0x0337, "disallowed");
    testIDNCharacter(0x0337, "disallowed");
    testIDNCharacter(0x0338, "disallowed");
    testIDNCharacter(0x0338, "disallowed");
    testIDNCharacter(0x05B4, "disallowed");
    testIDNCharacter(0x05BC, "disallowed");
    testIDNCharacter(0x0660, "disallowed");
    testIDNCharacter(0x06F0, "disallowed");
    testIDNCharacter(0x115F, "disallowed");
    testIDNCharacter(0x1160, "disallowed");
    testIDNCharacter(0x3164, "disallowed");
    testIDNCharacter(0x321D, "disallowed");
    testIDNCharacter(0x321E, "disallowed");
    testIDNCharacter(0xFE14, "disallowed");
    testIDNCharacter(0xFE15, "disallowed");
    testIDNCharacter(0xFFA0, "disallowed");
} else {
    testIDNCharacter(0x200B, "does not encode", "");
    testIDNCharacter(0x3002, "does not encode", ".");
    testIDNCharacter(0xFF0E, "does not encode", ".");
    testIDNCharacter(0xFF61, "does not encode", ".");
    testIDNCharacter(0xFEFF, "does not encode", "");
    testIDNCharacter(0x2024, "%u2024");
    testIDNCharacter(0xFE52, "%uFE52");
    testIDNCharacter(0x0337, "%u0337", "punycode");
    testIDNCharacter(0x0337, "%u0337", "punycode");
    testIDNCharacter(0x0338, "%u0338", "punycode");
    testIDNCharacter(0x0338, "%u0338", "punycode");
    testIDNCharacter(0x05B4, "%u05B4", "punycode");
    testIDNCharacter(0x05BC, "%u05BC", "punycode");
    testIDNCharacter(0x0660, "%u0660");
    testIDNCharacter(0x06F0, "disallowed");
    testIDNCharacter(0x115F, "%u115F");
    testIDNCharacter(0x1160, "%u1160");
    testIDNCharacter(0x3164, "%u3164");
    testIDNCharacter(0x321D, "%28%uC624%uC804%29");
    testIDNCharacter(0x321E, "%28%uC624%uD6C4%29");
    testIDNCharacter(0xFE14, "%3B");
    testIDNCharacter(0xFE15, "%21");
    testIDNCharacter(0xFFA0, "%uFFA0");
}

</script>
</body>
</html>
