Add unit tests for the service provider extensions

This commit is contained in:
Levi B 2015-02-27 14:15:41 -08:00
parent a1dbce9065
commit 04707ccaa0
7 changed files with 299 additions and 15 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
@ -12,13 +11,17 @@ namespace Microsoft.Framework.DependencyInjection
{
public static IServiceCollection AddWebEncoders([NotNull] this IServiceCollection services)
{
return AddWebEncoders(services, configuration: null);
return AddWebEncoders(services, configureOptions: null);
}
public static IServiceCollection AddWebEncoders([NotNull] this IServiceCollection services, IConfiguration configuration)
public static IServiceCollection AddWebEncoders([NotNull] this IServiceCollection services, Action<WebEncoderOptions> configureOptions)
{
services.AddOptions(configuration);
services.TryAdd(EncoderServices.GetDefaultServices(configuration));
services.AddOptions();
services.TryAdd(EncoderServices.GetDefaultServices());
if (configureOptions != null)
{
services.Configure(configureOptions);
}
return services;
}
}

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
@ -13,12 +12,7 @@ namespace Microsoft.Framework.WebEncoders
{
public static IEnumerable<IServiceDescriptor> GetDefaultServices()
{
return GetDefaultServices(configuration: null);
}
public static IEnumerable<IServiceDescriptor> GetDefaultServices(IConfiguration configuration)
{
var describe = new ServiceDescriber(configuration);
var describe = new ServiceDescriber();
// Register the default encoders
// We want to call the 'Default' property getters lazily since they perform static caching
@ -31,7 +25,7 @@ namespace Microsoft.Framework.WebEncoders
{
return serviceProvider =>
{
var codePointFilter = serviceProvider?.GetService<IOptions<EncoderOptions>>()?.Options?.CodePointFilter;
var codePointFilter = serviceProvider?.GetService<IOptions<WebEncoderOptions>>()?.Options?.CodePointFilter;
return (codePointFilter != null) ? customFilterFactory(codePointFilter) : defaultFactory();
};
}

View File

@ -8,7 +8,7 @@ namespace Microsoft.Framework.WebEncoders
/// <summary>
/// Specifies options common to all three encoders (HtmlEncode, JavaScriptStringEncode, UrlEncode).
/// </summary>
public sealed class EncoderOptions
public sealed class WebEncoderOptions
{
/// <summary>
/// Specifies which code points are allowed to be represented unescaped by the encoders.

View File

@ -5,7 +5,6 @@
"allowUnsafe": true
},
"dependencies": {
"Microsoft.Framework.ConfigurationModel": "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*",
"Microsoft.Framework.NotNullAttribute.Internal": { "type": "build", "version": "1.0.0-*" }

View File

@ -0,0 +1,103 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
namespace Microsoft.Framework.WebEncoders
{
/// <summary>
/// Dummy encoder used for unit testing.
/// </summary>
public sealed class CommonTestEncoder : IHtmlEncoder, IJavaScriptStringEncoder, IUrlEncoder
{
/// <summary>
/// Returns "HtmlEncode[[value]]".
/// </summary>
public string HtmlEncode(string value)
{
return EncodeCore(value);
}
/// <summary>
/// Writes "HtmlEncode[[value]]".
/// </summary>
public void HtmlEncode(string value, int startIndex, int charCount, TextWriter output)
{
EncodeCore(value, startIndex, charCount, output);
}
/// <summary>
/// Writes "HtmlEncode[[value]]".
/// </summary>
public void HtmlEncode(char[] value, int startIndex, int charCount, TextWriter output)
{
EncodeCore(value, startIndex, charCount, output);
}
/// <summary>
/// Returns "JavaScriptStringEncode[[value]]".
/// </summary>
public string JavaScriptStringEncode(string value)
{
return EncodeCore(value);
}
/// <summary>
/// Writes "JavaScriptStringEncode[[value]]".
/// </summary>
public void JavaScriptStringEncode(string value, int startIndex, int charCount, TextWriter output)
{
EncodeCore(value, startIndex, charCount, output);
}
/// <summary>
/// Writes "JavaScriptStringEncode[[value]]".
/// </summary>
public void JavaScriptStringEncode(char[] value, int startIndex, int charCount, TextWriter output)
{
EncodeCore(value, startIndex, charCount, output);
}
/// <summary>
/// Returns "UrlEncode[[value]]".
/// </summary>
public string UrlEncode(string value)
{
return EncodeCore(value);
}
/// <summary>
/// Writes "UrlEncode[[value]]".
/// </summary>
public void UrlEncode(string value, int startIndex, int charCount, TextWriter output)
{
EncodeCore(value, startIndex, charCount, output);
}
/// <summary>
/// Writes "UrlEncode[[value]]".
/// </summary>
public void UrlEncode(char[] value, int startIndex, int charCount, TextWriter output)
{
EncodeCore(value, startIndex, charCount, output);
}
private static string EncodeCore(string value, [CallerMemberName] string encodeType = null)
{
return String.Format(CultureInfo.InvariantCulture, "{0}[[{1}]]", encodeType, value);
}
private static void EncodeCore(string value, int startIndex, int charCount, TextWriter output, [CallerMemberName] string encodeType = null)
{
output.Write(EncodeCore(value.Substring(startIndex, charCount), encodeType));
}
private static void EncodeCore(char[] value, int startIndex, int charCount, TextWriter output, [CallerMemberName] string encodeType = null)
{
output.Write(EncodeCore(new string(value, startIndex, charCount), encodeType));
}
}
}

View File

@ -0,0 +1,88 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Xunit;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
namespace Microsoft.Framework.WebEncoders
{
public class EncoderServiceCollectionExtensionsTests
{
[Fact]
public void AddWebEncoders_WithoutOptions_RegistersDefaultEncoders()
{
// Arrange
var serviceCollection = new ServiceCollection();
// Act
serviceCollection.AddWebEncoders();
// Assert
var serviceProvider = serviceCollection.BuildServiceProvider();
Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService<IHtmlEncoder>()); // default encoder
Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService<IHtmlEncoder>()); // as singleton instance
Assert.Same(JavaScriptStringEncoder.Default, serviceProvider.GetRequiredService<IJavaScriptStringEncoder>()); // default encoder
Assert.Same(JavaScriptStringEncoder.Default, serviceProvider.GetRequiredService<IJavaScriptStringEncoder>()); // as singleton instance
Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService<IUrlEncoder>()); // default encoder
Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService<IUrlEncoder>()); // as singleton instance
}
[Fact]
public void AddWebEncoders_WithOptions_RegistersEncodersWithCustomCodeFilter()
{
// Arrange
var serviceCollection = new ServiceCollection();
// Act
serviceCollection.AddWebEncoders(options =>
{
options.CodePointFilter = new CodePointFilter().AllowChars("ace"); // only these three chars are allowed
});
// Assert
var serviceProvider = serviceCollection.BuildServiceProvider();
var htmlEncoder = serviceProvider.GetRequiredService<IHtmlEncoder>();
Assert.Equal("a&#x62;c&#x64;e", htmlEncoder.HtmlEncode("abcde"));
Assert.Same(htmlEncoder, serviceProvider.GetRequiredService<IHtmlEncoder>()); // as singleton instance
var javaScriptStringEncoder = serviceProvider.GetRequiredService<IJavaScriptStringEncoder>();
Assert.Equal(@"a\u0062c\u0064e", javaScriptStringEncoder.JavaScriptStringEncode("abcde"));
Assert.Same(javaScriptStringEncoder, serviceProvider.GetRequiredService<IJavaScriptStringEncoder>()); // as singleton instance
var urlEncoder = serviceProvider.GetRequiredService<IUrlEncoder>();
Assert.Equal("a%62c%64e", urlEncoder.UrlEncode("abcde"));
Assert.Same(urlEncoder, serviceProvider.GetRequiredService<IUrlEncoder>()); // as singleton instance
}
[Fact]
public void AddWebEncoders_DoesNotOverrideExistingRegisteredEncoders()
{
// Arrange
var serviceCollection = new ServiceCollection();
// Act
serviceCollection.AddSingleton<IHtmlEncoder, CommonTestEncoder>();
serviceCollection.AddSingleton<IJavaScriptStringEncoder, CommonTestEncoder>();
// we don't register an existing URL encoder
serviceCollection.AddWebEncoders(options =>
{
options.CodePointFilter = new CodePointFilter().AllowChars("ace"); // only these three chars are allowed
});
// Assert
var serviceProvider = serviceCollection.BuildServiceProvider();
var htmlEncoder = serviceProvider.GetHtmlEncoder();
Assert.Equal("HtmlEncode[[abcde]]", htmlEncoder.HtmlEncode("abcde"));
var javaScriptStringEncoder = serviceProvider.GetJavaScriptStringEncoder();
Assert.Equal("JavaScriptStringEncode[[abcde]]", javaScriptStringEncoder.JavaScriptStringEncode("abcde"));
var urlEncoder = serviceProvider.GetUrlEncoder();
Assert.Equal("a%62c%64e", urlEncoder.UrlEncode("abcde"));
}
}
}

View File

@ -0,0 +1,97 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using Moq;
using Xunit;
namespace Microsoft.Framework.WebEncoders
{
public class EncoderServiceProviderExtensionsTests
{
[Fact]
public void GetHtmlEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault()
{
// Arrange
var serviceProvider = new Mock<IServiceProvider>().Object;
// Act
var retVal = serviceProvider.GetHtmlEncoder();
// Assert
Assert.Same(HtmlEncoder.Default, retVal);
}
[Fact]
public void GetHtmlEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance()
{
// Arrange
var expectedEncoder = new Mock<IHtmlEncoder>().Object;
var mockServiceProvider = new Mock<IServiceProvider>();
mockServiceProvider.Setup(o => o.GetService(typeof(IHtmlEncoder))).Returns(expectedEncoder);
// Act
var retVal = mockServiceProvider.Object.GetHtmlEncoder();
// Assert
Assert.Same(expectedEncoder, retVal);
}
[Fact]
public void GetJavaScriptStringEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault()
{
// Arrange
var serviceProvider = new Mock<IServiceProvider>().Object;
// Act
var retVal = serviceProvider.GetJavaScriptStringEncoder();
// Assert
Assert.Same(JavaScriptStringEncoder.Default, retVal);
}
[Fact]
public void GetJavaScriptStringEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance()
{
// Arrange
var expectedEncoder = new Mock<IJavaScriptStringEncoder>().Object;
var mockServiceProvider = new Mock<IServiceProvider>();
mockServiceProvider.Setup(o => o.GetService(typeof(IJavaScriptStringEncoder))).Returns(expectedEncoder);
// Act
var retVal = mockServiceProvider.Object.GetJavaScriptStringEncoder();
// Assert
Assert.Same(expectedEncoder, retVal);
}
[Fact]
public void GetUrlEncoder_ServiceProviderDoesNotHaveEncoder_UsesDefault()
{
// Arrange
var serviceProvider = new Mock<IServiceProvider>().Object;
// Act
var retVal = serviceProvider.GetUrlEncoder();
// Assert
Assert.Same(UrlEncoder.Default, retVal);
}
[Fact]
public void GetUrlEncoder_ServiceProviderHasEncoder_ReturnsRegisteredInstance()
{
// Arrange
var expectedEncoder = new Mock<IUrlEncoder>().Object;
var mockServiceProvider = new Mock<IServiceProvider>();
mockServiceProvider.Setup(o => o.GetService(typeof(IUrlEncoder))).Returns(expectedEncoder);
// Act
var retVal = mockServiceProvider.Object.GetUrlEncoder();
// Assert
Assert.Same(expectedEncoder, retVal);
}
}
}