public void JavaScriptStringEncode_NullInput_Throws() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); Assert.Throws <ArgumentNullException>(() => { encoder.JavaScriptStringEncode(null); }); }
public void JavaScriptStringEncode_NullInput_Throws_Relaxed() { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; Assert.Throws <ArgumentNullException>(() => { encoder.JavaScriptStringEncode(null); }); }
public void JavaScriptStringEncode_NoRangesAllowed_EmitsShortFormForCertainCodePoints() { // This test ensures that when we're encoding, we always emit the "\uXXXX" form of the // code point except for very specific code points where we allow a shorter representation. // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.None); // allow no codepoints // "[U+0000][U+0001]...[U+007F]" string input = new string(Enumerable.Range(0, 128).Select(i => (char)i).ToArray()); // @"\u0000\u0001..\u007F", then replace certain specific code points string expected = string.Concat(Enumerable.Range(0, 128).Select(i => FormattableString.Invariant($@"\u{i:X4}"))); expected = expected.Replace(@"\u0008", @"\b"); // U+0008 BACKSPACE -> "\b" expected = expected.Replace(@"\u0009", @"\t"); // U+0009 CHARACTER TABULATION -> "\t" expected = expected.Replace(@"\u000A", @"\n"); // U+000A LINE FEED -> "\n" expected = expected.Replace(@"\u000C", @"\f"); // U+000C FORM FEED -> "\f" expected = expected.Replace(@"\u000D", @"\r"); // U+000D CARRIAGE RETURN -> "\n" expected = expected.Replace(@"\u005C", @"\\"); // U+005C REVERSE SOLIDUS -> "\\" // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void JavaScriptStringEncode_EmptyStringInput_ReturnsEmptyString() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); // Act & assert Assert.Equal("", encoder.JavaScriptStringEncode("")); }
public void JavaScriptStringEncode_NullInput_ReturnsNull() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); // Act & assert Assert.Null(encoder.JavaScriptStringEncode(null)); }
public void JavaScriptStringEncode_EmptyStringInput_ReturnsEmptyString_Relaxed() { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act & assert Assert.Equal("", encoder.JavaScriptStringEncode("")); }
public void Default_ReturnsSingletonInstance() { // Act JavaScriptStringEncoder encoder1 = JavaScriptStringEncoder.Default; JavaScriptStringEncoder encoder2 = JavaScriptStringEncoder.Default; // Assert Assert.Same(encoder1, encoder2); }
public void JavaScriptStringEncode_InputDoesNotRequireEncoding_ReturnsOriginalStringInstance() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); string input = "Hello, there!"; // Act & assert Assert.Same(input, encoder.JavaScriptStringEncode(input)); }
public void JavaScriptStringEncode_InputDoesNotRequireEncoding_ReturnsOriginalStringInstance_Relaxed() { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; string input = "Hello, there!"; // Act & assert Assert.Same(input, encoder.JavaScriptStringEncode(input)); }
public void Ctor_WithNoParameters_DefaultsToBasicLatin() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); // Act & assert Assert.Equal("a", encoder.JavaScriptStringEncode("a")); Assert.Equal(@"\u00E9", encoder.JavaScriptStringEncode("\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */)); Assert.Equal(@"\u2601", encoder.JavaScriptStringEncode("\u2601" /* CLOUD */)); }
public void Ctor_WithUnicodeRanges() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.Latin1Supplement, UnicodeRanges.MiscellaneousSymbols); // Act & assert Assert.Equal(@"\u0061", encoder.JavaScriptStringEncode("a")); Assert.Equal("\u00E9", encoder.JavaScriptStringEncode("\u00E9" /* LATIN SMALL LETTER E WITH ACUTE */)); Assert.Equal("\u2601", encoder.JavaScriptStringEncode("\u2601" /* CLOUD */)); }
public void JavaScriptStringEncode_Relaxed_StillEncodesForbiddenChars_Simple(string input, string expected) { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void JavaScriptStringEncode_AllRangesAllowed_StillEncodesForbiddenChars_Simple(string input, string expected) { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.All); // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void JavaScriptStringEncode_Quotes_Relaxed(string input, string expected) { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void JavaScriptStringEncode_DoesOutputHtmlSensitiveCharacters_Relaxed(string input, string expected) { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void JavaScriptStringEncode_PositiveTestCase() { // Arrange IJavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.All); StringWriter writer = new StringWriter(); // Act encoder.JavaScriptStringEncode("Hello+there!", writer); // Assert Assert.Equal(@"Hello\u002Bthere!", writer.ToString()); }
public void JavaScriptStringEncode_StringSubstring() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); var output = new StringWriter(); // Act encoder.JavaScriptStringEncode("Hello+world!", 3, 5, output); // Assert Assert.Equal(@"lo\u002Bwo", output.ToString()); }
public void GetJavaScriptStringEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance() { // Arrange var expectedEncoder = new JavaScriptStringEncoder(); var serviceProvider = new TestServiceProvider() { Service = expectedEncoder }; // Act var retVal = serviceProvider.GetJavaScriptStringEncoder(); // Assert Assert.Same(expectedEncoder, retVal); }
public void JavaScriptStringEncode_StringSubstring_Relaxed() { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; using var output = new StringWriter(); // Act encoder.JavaScriptStringEncode("Hello\\world!", 3, 5, output); // Assert Assert.Equal(@"lo\\wo", output.ToString()); }
public void Ctor_WithCodePointFilter() { // Arrange var filter = new CodePointFilter().AllowChars("ab").AllowChars('\0', '&', '\uFFFF', 'd'); JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(filter); // Act & assert Assert.Equal("a", encoder.JavaScriptStringEncode("a")); Assert.Equal("b", encoder.JavaScriptStringEncode("b")); Assert.Equal(@"\u0063", encoder.JavaScriptStringEncode("c")); Assert.Equal("d", encoder.JavaScriptStringEncode("d")); Assert.Equal(@"\u0000", encoder.JavaScriptStringEncode("\0")); // we still always encode control chars Assert.Equal(@"\u0026", encoder.JavaScriptStringEncode("&")); // we still always encode HTML-special chars Assert.Equal(@"\uFFFF", encoder.JavaScriptStringEncode("\uFFFF")); // we still always encode non-chars and other forbidden chars }
public void JavaScriptStringEncode_BadSurrogates_ReturnsUnicodeReplacementChar() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.All); // allow all codepoints // "a<unpaired leading>b<unpaired trailing>c<trailing before leading>d<unpaired trailing><valid>e<high at end of string>" const string input = "a\uD800b\uDFFFc\uDFFF\uD800d\uDFFF\uD800\uDFFFe\uD800"; const string expected = "a\uFFFDb\uFFFDc\uFFFD\uFFFDd\uFFFD\\uD800\\uDFFFe\uFFFD"; // 'D800' 'DFFF' was preserved since it's valid // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void JavaScriptStringEncode_Quotes(string input, string expected) { // Per the design document, we provide additional defense-in-depth // against breaking out of HTML attributes by having the encoders // never emit the ' or " characters. This means that we want to // \u-escape these characters instead of using \' and \". // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.All); // Act string retVal = encoder.JavaScriptStringEncode(input); // Assert Assert.Equal(expected, retVal); }
public void Default_EquivalentToBasicLatin() { // Arrange JavaScriptStringEncoder controlEncoder = new JavaScriptStringEncoder(UnicodeRanges.BasicLatin); JavaScriptStringEncoder testEncoder = JavaScriptStringEncoder.Default; // Act & assert for (int i = 0; i <= Char.MaxValue; i++) { if (!IsSurrogateCodePoint(i)) { string input = new String((char)i, 1); Assert.Equal(controlEncoder.JavaScriptStringEncode(input), testEncoder.JavaScriptStringEncode(input)); } } }
public void JavaScriptStringEncode_ControlCharacters_Relaxed() { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act & assert for (int i = 0; i <= 0x1F; i++) { // Skip characters that are escaped using '\\' since they are covered in other tests. if (i == '\b' || i == '\f' || i == '\n' || i == '\r' || i == '\t') { continue; } string javaScriptStringEncoded = encoder.JavaScriptStringEncode(char.ConvertFromUtf32(i)); string expected = string.Format("\\u00{0:X2}", i); Assert.Equal(expected, javaScriptStringEncoded); } }
public void JavaScriptStringEncode_DoesNotOutputHtmlSensitiveCharacters() { // Per the design document, we provide additional defense-in-depth // by never emitting HTML-sensitive characters unescaped. // Arrange JavaScriptStringEncoder javaScriptStringEncoder = new JavaScriptStringEncoder(UnicodeRanges.All); HtmlEncoder htmlEncoder = new HtmlEncoder(UnicodeRanges.All); // Act & assert for (int i = 0; i <= 0x10FFFF; i++) { if (IsSurrogateCodePoint(i)) { continue; // surrogates don't matter here } string javaScriptStringEncoded = javaScriptStringEncoder.JavaScriptStringEncode(Char.ConvertFromUtf32(i)); string thenHtmlEncoded = htmlEncoder.HtmlEncode(javaScriptStringEncoded); Assert.Equal(javaScriptStringEncoded, thenHtmlEncoded); // should have contained no HTML-sensitive characters } }
public void Relaxed_EquivalentToAll_WithExceptions() { // Arrange JavaScriptStringEncoder controlEncoder = new JavaScriptStringEncoder(UnicodeRanges.All); JavaScriptStringEncoder testEncoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act & assert for (int i = 0; i <= char.MaxValue; i++) { if (i == '"' || i == '&' || i == '<' || i == '>' || i == '+' || i == '\'' || i == '`') { string input = new string((char)i, 1); Assert.NotEqual(controlEncoder.JavaScriptStringEncode(input), testEncoder.JavaScriptStringEncode(input)); continue; } if (!IsSurrogateCodePoint(i)) { string input = new string((char)i, 1); Assert.Equal(controlEncoder.JavaScriptStringEncode(input), testEncoder.JavaScriptStringEncode(input)); } } }
public void JavaScriptStringEncode_AboveAscii_Relaxed() { // Arrange JavaScriptStringEncoder encoder = JavaScriptStringEncoder.UnsafeRelaxedJsonEscaping; // Act & assert for (int i = 0x128; i <= 0xFFFF; i++) { if (IsSurrogateCodePoint(i)) { continue; // surrogates don't matter here } UnicodeCategory category = char.GetUnicodeCategory((char)i); if (category != UnicodeCategory.NonSpacingMark) { continue; // skip undefined characters like U+0378, or spacing characters like U+2028 } string javaScriptStringEncoded = encoder.JavaScriptStringEncode(char.ConvertFromUtf32(i)); Assert.True(char.ConvertFromUtf32(i) == javaScriptStringEncoded, i.ToString()); } }
[MethodImpl(MethodImplOptions.NoInlining)] // the JITter can attempt to inline the caller itself without worrying about us private static JavaScriptStringEncoder CreateDefaultEncoderSlow() { var onDemandEncoder = new JavaScriptStringEncoder(); return(Interlocked.CompareExchange(ref _defaultEncoder, onDemandEncoder, null) ?? onDemandEncoder); }
public void JavaScriptStringEncode_AllRangesAllowed_StillEncodesForbiddenChars_Extended() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.All); // Act & assert - BMP chars for (int i = 0; i <= 0xFFFF; i++) { string input = new String((char)i, 1); string expected; if (IsSurrogateCodePoint(i)) { expected = "\uFFFD"; // unpaired surrogate -> Unicode replacement char } else { if (input == "\b") { expected = @"\b"; } else if (input == "\t") { expected = @"\t"; } else if (input == "\n") { expected = @"\n"; } else if (input == "\f") { expected = @"\f"; } else if (input == "\r") { expected = @"\r"; } else if (input == "\\") { expected = @"\\"; } else if (input == "/") { expected = @"\/"; } else if (input == "`") { expected = @"\u0060"; } else { bool mustEncode = false; switch (i) { case '<': case '>': case '&': case '\"': case '\'': case '+': mustEncode = true; break; } if (i <= 0x001F || (0x007F <= i && i <= 0x9F)) { mustEncode = true; // control char } else if (!UnicodeHelpers.IsCharacterDefined((char)i)) { mustEncode = true; // undefined (or otherwise disallowed) char } if (mustEncode) { expected = String.Format(CultureInfo.InvariantCulture, @"\u{0:X4}", i); } else { expected = input; // no encoding } } } string retVal = encoder.JavaScriptStringEncode(input); Assert.Equal(expected, retVal); } // Act & assert - astral chars for (int i = 0x10000; i <= 0x10FFFF; i++) { string input = Char.ConvertFromUtf32(i); string expected = String.Format(CultureInfo.InvariantCulture, @"\u{0:X4}\u{1:X4}", (uint)input[0], (uint)input[1]); string retVal = encoder.JavaScriptStringEncode(input); Assert.Equal(expected, retVal); } }
public void JavaScriptStringEncode_NullInput_Throws() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(); Assert.Throws<ArgumentNullException>(() => { encoder.JavaScriptStringEncode(null); }); }
[MethodImpl(MethodImplOptions.NoInlining)] // the JITter can attempt to inline the caller itself without worrying about us private static JavaScriptStringEncoder CreateDefaultEncoderSlow() { var onDemandEncoder = new JavaScriptStringEncoder(); return Interlocked.CompareExchange(ref _defaultEncoder, onDemandEncoder, null) ?? onDemandEncoder; }
public void JavaScriptStringEncode_AllRangesAllowed_StillEncodesForbiddenChars_Extended() { // Arrange JavaScriptStringEncoder encoder = new JavaScriptStringEncoder(UnicodeRanges.All); // Act & assert - BMP chars for (int i = 0; i <= 0xFFFF; i++) { string input = new String((char)i, 1); string expected; if (IsSurrogateCodePoint(i)) { expected = "\uFFFD"; // unpaired surrogate -> Unicode replacement char } else { if (input == "\b") { expected = @"\b"; } else if (input == "\t") { expected = @"\t"; } else if (input == "\n") { expected = @"\n"; } else if (input == "\f") { expected = @"\f"; } else if (input == "\r") { expected = @"\r"; } else if (input == "\\") { expected = @"\\"; } else if (input == "/") { expected = @"\/"; } else { bool mustEncode = false; switch (i) { case '<': case '>': case '&': case '\"': case '\'': case '+': mustEncode = true; break; } if (i <= 0x001F || (0x007F <= i && i <= 0x9F)) { mustEncode = true; // control char } else if (!UnicodeHelpers.IsCharacterDefined((char)i)) { mustEncode = true; // undefined (or otherwise disallowed) char } if (mustEncode) { expected = String.Format(CultureInfo.InvariantCulture, @"\u{0:X4}", i); } else { expected = input; // no encoding } } } string retVal = encoder.JavaScriptStringEncode(input); Assert.Equal(expected, retVal); } // Act & assert - astral chars for (int i = 0x10000; i <= 0x10FFFF; i++) { string input = Char.ConvertFromUtf32(i); string expected = String.Format(CultureInfo.InvariantCulture, @"\u{0:X4}\u{1:X4}", (uint)input[0], (uint)input[1]); string retVal = encoder.JavaScriptStringEncode(input); Assert.Equal(expected, retVal); } }