Removed Moq from tests & enabled .NET Core

- Introduced AssemblyWrapper to enable testing
- Cleaned up properties on ResourceManagerStringLocalizer
- #15

Change "Strategy" to "Provider"
- #19
This commit is contained in:
damianedwards 2015-05-20 11:56:47 -07:00
parent 9384848cc7
commit 4ba159afe7
17 changed files with 166 additions and 143 deletions

View File

@ -36,9 +36,9 @@ namespace LocalizationSample
//} //}
}; };
// Optionally create an app-specific strategy with just a delegate, e.g. look up user preference from DB. // Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
// Inserting it as position 0 ensures it has priority over any of the default strategies. // Inserting it as position 0 ensures it has priority over any of the default providers.
//options.RequestCultureStrategies.Insert(0, new CustomRequestCultureStrategy(async context => //options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
//{ //{
//})); //}));
@ -74,13 +74,13 @@ $@"<!doctype html>
function useCookie() {{ function useCookie() {{
var culture = document.getElementById('culture'); var culture = document.getElementById('culture');
var uiCulture = document.getElementById('uiCulture'); var uiCulture = document.getElementById('uiCulture');
var cookieValue = '{CookieRequestCultureStrategy.DefaultCookieName}=c='+culture.options[culture.selectedIndex].value+'|uic='+uiCulture.options[uiCulture.selectedIndex].value; var cookieValue = '{CookieRequestCultureProvider.DefaultCookieName}=c='+culture.options[culture.selectedIndex].value+'|uic='+uiCulture.options[uiCulture.selectedIndex].value;
document.cookie = cookieValue; document.cookie = cookieValue;
window.location = window.location.href.split('?')[0]; window.location = window.location.href.split('?')[0];
}} }}
function clearCookie() {{ function clearCookie() {{
document.cookie='{CookieRequestCultureStrategy.DefaultCookieName}=""""'; document.cookie='{CookieRequestCultureProvider.DefaultCookieName}=""""';
}} }}
</script> </script>
</head> </head>
@ -101,7 +101,7 @@ $@"<!doctype html>
await context.Response.WriteAsync("</form>"); await context.Response.WriteAsync("</form>");
await context.Response.WriteAsync("<br />"); await context.Response.WriteAsync("<br />");
await context.Response.WriteAsync("<table><tbody>"); await context.Response.WriteAsync("<table><tbody>");
await context.Response.WriteAsync($"<tr><th>Winning strategy:</th><td>{requestCultureFeature.Strategy.GetType().Name}</td></tr>"); await context.Response.WriteAsync($"<tr><th>Winning provider:</th><td>{requestCultureFeature.Provider.GetType().Name}</td></tr>");
await context.Response.WriteAsync($"<tr><th>{SR["Current request culture:"]}</th><td>{requestCulture.Culture.DisplayName} ({requestCulture.Culture})</td></tr>"); await context.Response.WriteAsync($"<tr><th>{SR["Current request culture:"]}</th><td>{requestCulture.Culture.DisplayName} ({requestCulture.Culture})</td></tr>");
await context.Response.WriteAsync($"<tr><th>{SR["Current request UI culture:"]}</th><td>{requestCulture.UICulture.DisplayName} ({requestCulture.UICulture})</td></tr>"); await context.Response.WriteAsync($"<tr><th>{SR["Current request UI culture:"]}</th><td>{requestCulture.UICulture.DisplayName} ({requestCulture.UICulture})</td></tr>");
await context.Response.WriteAsync($"<tr><th>{SR["Current thread culture:"]}</th><td>{CultureInfo.CurrentCulture.DisplayName} ({CultureInfo.CurrentCulture})</td></tr>"); await context.Response.WriteAsync($"<tr><th>{SR["Current thread culture:"]}</th><td>{CultureInfo.CurrentCulture.DisplayName} ({CultureInfo.CurrentCulture})</td></tr>");

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Localization
/// <summary> /// <summary>
/// Determines the culture information for a request via the value of the Accept-Language header. /// Determines the culture information for a request via the value of the Accept-Language header.
/// </summary> /// </summary>
public class AcceptLanguageHeaderRequestCultureStrategy : RequestCultureStrategy public class AcceptLanguageHeaderRequestCultureProvider : RequestCultureProvider
{ {
/// <summary> /// <summary>
/// The maximum number of values in the Accept-Language header to attempt to create a <see cref="System.Globalization.CultureInfo"/> /// The maximum number of values in the Accept-Language header to attempt to create a <see cref="System.Globalization.CultureInfo"/>

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Localization
/// <summary> /// <summary>
/// Determines the culture information for a request via the value of a cookie. /// Determines the culture information for a request via the value of a cookie.
/// </summary> /// </summary>
public class CookieRequestCultureStrategy : RequestCultureStrategy public class CookieRequestCultureProvider : RequestCultureProvider
{ {
private static readonly char[] _cookieSeparator = new[] { '|' }; private static readonly char[] _cookieSeparator = new[] { '|' };
private static readonly string _culturePrefix = "c="; private static readonly string _culturePrefix = "c=";

View File

@ -11,23 +11,23 @@ namespace Microsoft.AspNet.Localization
/// <summary> /// <summary>
/// Determines the culture information for a request via the configured delegate. /// Determines the culture information for a request via the configured delegate.
/// </summary> /// </summary>
public class CustomRequestCultureStrategy : RequestCultureStrategy public class CustomRequestCultureProvider : RequestCultureProvider
{ {
private readonly Func<HttpContext, Task<RequestCulture>> _strategy; private readonly Func<HttpContext, Task<RequestCulture>> _provider;
/// <summary> /// <summary>
/// Creates a new <see cref="CustomRequestCultureStrategy"/> using the specified delegate. /// Creates a new <see cref="CustomRequestCultureProvider"/> using the specified delegate.
/// </summary> /// </summary>
/// <param name="strategy">The strategy delegate.</param> /// <param name="provider">The provider delegate.</param>
public CustomRequestCultureStrategy([NotNull] Func<HttpContext, Task<RequestCulture>> strategy) public CustomRequestCultureProvider([NotNull] Func<HttpContext, Task<RequestCulture>> provider)
{ {
_strategy = strategy; _provider = provider;
} }
/// <inheritdoc /> /// <inheritdoc />
public override Task<RequestCulture> DetermineRequestCulture([NotNull] HttpContext httpContext) public override Task<RequestCulture> DetermineRequestCulture([NotNull] HttpContext httpContext)
{ {
return _strategy(httpContext); return _provider(httpContext);
} }
} }
} }

View File

@ -14,10 +14,10 @@ namespace Microsoft.AspNet.Localization
RequestCulture RequestCulture { get; } RequestCulture RequestCulture { get; }
/// <summary> /// <summary>
/// The <see cref="IRequestCultureStrategy"/> that determined the request's culture information. /// The <see cref="IRequestCultureProvider"/> that determined the request's culture information.
/// If the value is <c>null</c> then no strategy was used and the request's culture was set to the value of /// If the value is <c>null</c> then no provider was used and the request's culture was set to the value of
/// <see cref="RequestLocalizationOptions.DefaultRequestCulture"/>. /// <see cref="RequestLocalizationOptions.DefaultRequestCulture"/>.
/// </summary> /// </summary>
IRequestCultureStrategy Strategy { get; } IRequestCultureProvider Provider { get; }
} }
} }

View File

@ -7,17 +7,17 @@ using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Localization namespace Microsoft.AspNet.Localization
{ {
/// <summary> /// <summary>
/// Represents a strategy for determining the culture information of an <see cref="HttpRequest"/>. /// Represents a provider for determining the culture information of an <see cref="HttpRequest"/>.
/// </summary> /// </summary>
public interface IRequestCultureStrategy public interface IRequestCultureProvider
{ {
/// <summary> /// <summary>
/// Implements the strategy to determine the culture of the given request. /// Implements the provider to determine the culture of the given request.
/// </summary> /// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> for the request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> for the request.</param>
/// <returns> /// <returns>
/// The determined <see cref="RequestCulture"/>. /// The determined <see cref="RequestCulture"/>.
/// Returns <c>null</c> if the strategy couldn't determine a <see cref="RequestCulture"/>. /// Returns <c>null</c> if the provider couldn't determine a <see cref="RequestCulture"/>.
/// </returns> /// </returns>
Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext); Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext);
} }

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Localization
/// <summary> /// <summary>
/// Determines the culture information for a request via values in the query string. /// Determines the culture information for a request via values in the query string.
/// </summary> /// </summary>
public class QueryStringRequestCultureStrategy : RequestCultureStrategy public class QueryStringRequestCultureProvider : RequestCultureProvider
{ {
/// <summary> /// <summary>
/// The key that contains the culture name. /// The key that contains the culture name.

View File

@ -14,16 +14,16 @@ namespace Microsoft.AspNet.Localization
/// Creates a new <see cref="RequestCultureFeature"/> with the specified <see cref="Localization.RequestCulture"/>. /// Creates a new <see cref="RequestCultureFeature"/> with the specified <see cref="Localization.RequestCulture"/>.
/// </summary> /// </summary>
/// <param name="requestCulture">The <see cref="Localization.RequestCulture"/>.</param> /// <param name="requestCulture">The <see cref="Localization.RequestCulture"/>.</param>
public RequestCultureFeature([NotNull] RequestCulture requestCulture, IRequestCultureStrategy strategy) public RequestCultureFeature([NotNull] RequestCulture requestCulture, IRequestCultureProvider provider)
{ {
RequestCulture = requestCulture; RequestCulture = requestCulture;
Strategy = strategy; Provider = provider;
} }
/// <inheritdoc /> /// <inheritdoc />
public RequestCulture RequestCulture { get; } public RequestCulture RequestCulture { get; }
/// <inheritdoc /> /// <inheritdoc />
public IRequestCultureStrategy Strategy { get; } public IRequestCultureProvider Provider { get; }
} }
} }

View File

@ -3,14 +3,13 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Localization namespace Microsoft.AspNet.Localization
{ {
/// <summary> /// <summary>
/// An abstract base class strategy for determining the culture information of an <see cref="HttpRequest"/>. /// An abstract base class provider for determining the culture information of an <see cref="HttpRequest"/>.
/// </summary> /// </summary>
public abstract class RequestCultureStrategy : IRequestCultureStrategy public abstract class RequestCultureProvider : IRequestCultureProvider
{ {
/// <summary> /// <summary>
/// The current options for the <see cref="RequestLocalizationMiddleware"/>. /// The current options for the <see cref="RequestLocalizationMiddleware"/>.

View File

@ -40,23 +40,23 @@ namespace Microsoft.AspNet.Localization
var requestCulture = _options.DefaultRequestCulture ?? var requestCulture = _options.DefaultRequestCulture ??
new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture); new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
IRequestCultureStrategy winningStrategy = null; IRequestCultureProvider winningProvider = null;
if (_options.RequestCultureStrategies != null) if (_options.RequestCultureProviders != null)
{ {
foreach (var strategy in _options.RequestCultureStrategies) foreach (var provider in _options.RequestCultureProviders)
{ {
var result = await strategy.DetermineRequestCulture(context); var result = await provider.DetermineRequestCulture(context);
if (result != null) if (result != null)
{ {
requestCulture = result; requestCulture = result;
winningStrategy = strategy; winningProvider = provider;
break; break;
} }
} }
} }
context.SetFeature<IRequestCultureFeature>(new RequestCultureFeature(requestCulture, winningStrategy)); context.SetFeature<IRequestCultureFeature>(new RequestCultureFeature(requestCulture, winningProvider));
SetCurrentThreadCulture(requestCulture); SetCurrentThreadCulture(requestCulture);

View File

@ -19,17 +19,17 @@ namespace Microsoft.AspNet.Localization
{ {
DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture); DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
RequestCultureStrategies = new List<IRequestCultureStrategy> RequestCultureProviders = new List<IRequestCultureProvider>
{ {
new QueryStringRequestCultureStrategy { Options = this }, new QueryStringRequestCultureProvider { Options = this },
new CookieRequestCultureStrategy { Options = this }, new CookieRequestCultureProvider { Options = this },
new AcceptLanguageHeaderRequestCultureStrategy { Options = this } new AcceptLanguageHeaderRequestCultureProvider { Options = this }
}; };
} }
/// <summary> /// <summary>
/// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured /// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured
/// <see cref="IRequestCultureStrategy"/> options result in a non-<c>null</c> result. /// <see cref="IRequestCultureProvider"/> options result in a non-<c>null</c> result.
/// Defaults to <see cref="RequestCulture.Culture"/> set to <see cref="CultureInfo.DefaultThreadCurrentCulture"/> /// Defaults to <see cref="RequestCulture.Culture"/> set to <see cref="CultureInfo.DefaultThreadCurrentCulture"/>
/// and <see cref="RequestCulture.UICulture"/> set to <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>. /// and <see cref="RequestCulture.UICulture"/> set to <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>.
/// </summary> /// </summary>
@ -54,16 +54,16 @@ namespace Microsoft.AspNet.Localization
public IList<CultureInfo> SupportedUICultures { get; set; } public IList<CultureInfo> SupportedUICultures { get; set; }
/// <summary> /// <summary>
/// An ordered list of strategies used to determine a request's culture information. The first strategy that /// An ordered list of providers used to determine a request's culture information. The first provider that
/// returns a non-<c>null</c> result for a given request will be used. /// returns a non-<c>null</c> result for a given request will be used.
/// Defaults to the following: /// Defaults to the following:
/// <list type="number"> /// <list type="number">
/// <item><description><see cref="QueryStringRequestCultureStrategy"/></description></item> /// <item><description><see cref="QueryStringRequestCultureProvider"/></description></item>
/// <item><description><see cref="CookieRequestCultureStrategy"/></description></item> /// <item><description><see cref="CookieRequestCultureProvider"/></description></item>
/// <item><description><see cref="AcceptLanguageHeaderRequestCultureStrategy"/></description></item> /// <item><description><see cref="AcceptLanguageHeaderRequestCultureProvider"/></description></item>
/// </list> /// </list>
/// </summary> /// </summary>
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Improves usability")] [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Improves usability")]
public IList<IRequestCultureStrategy> RequestCultureStrategies { get; set; } public IList<IRequestCultureProvider> RequestCultureProviders { get; set; }
} }
} }

View File

@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.Framework.Localization.Internal
{
public class AssemblyWrapper
{
public AssemblyWrapper([NotNull] Assembly assembly)
{
Assembly = assembly;
}
public Assembly Assembly { get; }
public virtual string FullName => Assembly.FullName;
public virtual Stream GetManifestResourceStream(string name) => Assembly.GetManifestResourceStream(name);
}
}

View File

@ -9,6 +9,7 @@ using System.Globalization;
using System.Reflection; using System.Reflection;
using System.Resources; using System.Resources;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization.Internal;
namespace Microsoft.Framework.Localization namespace Microsoft.Framework.Localization
{ {
@ -18,12 +19,16 @@ namespace Microsoft.Framework.Localization
/// </summary> /// </summary>
public class ResourceManagerStringLocalizer : IStringLocalizer public class ResourceManagerStringLocalizer : IStringLocalizer
{ {
private static readonly ConcurrentDictionary<string, IList<string>> _resourceNamesCache =
new ConcurrentDictionary<string, IList<string>>();
private readonly ConcurrentDictionary<string, object> _missingManifestCache = private readonly ConcurrentDictionary<string, object> _missingManifestCache =
new ConcurrentDictionary<string, object>(); new ConcurrentDictionary<string, object>();
private static readonly ConcurrentDictionary<string, IList<string>> _resourceNamesCache = private readonly ResourceManager _resourceManager;
new ConcurrentDictionary<string, IList<string>>(); private readonly AssemblyWrapper _resourceAssemblyWrapper;
private readonly string _resourceBaseName;
/// <summary> /// <summary>
/// Creates a new <see cref="ResourceManagerStringLocalizer"/>. /// Creates a new <see cref="ResourceManagerStringLocalizer"/>.
/// </summary> /// </summary>
@ -34,26 +39,23 @@ namespace Microsoft.Framework.Localization
[NotNull] ResourceManager resourceManager, [NotNull] ResourceManager resourceManager,
[NotNull] Assembly resourceAssembly, [NotNull] Assembly resourceAssembly,
[NotNull] string baseName) [NotNull] string baseName)
: this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName)
{ {
ResourceManager = resourceManager;
ResourceAssembly = resourceAssembly;
ResourceBaseName = baseName;
} }
/// <summary> /// <summary>
/// The <see cref="System.Resources.ResourceManager"/> to read strings from. /// Intended for testing purposes only.
/// </summary> /// </summary>
protected ResourceManager ResourceManager { get; } public ResourceManagerStringLocalizer(
[NotNull] ResourceManager resourceManager,
/// <summary> [NotNull] AssemblyWrapper resourceAssemblyWrapper,
/// The <see cref="Assembly"/> that contains the strings as embedded resources. [NotNull] string baseName)
/// </summary> {
protected Assembly ResourceAssembly { get; } _resourceAssemblyWrapper = resourceAssemblyWrapper;
_resourceManager = resourceManager;
/// <summary> _resourceBaseName = baseName;
/// The base name of the embedded resource in the <see cref="Assembly"/> that contains the strings. }
/// </summary>
protected string ResourceBaseName { get; }
/// <inheritdoc /> /// <inheritdoc />
public virtual LocalizedString this[[NotNull] string name] public virtual LocalizedString this[[NotNull] string name]
@ -84,16 +86,15 @@ namespace Microsoft.Framework.Localization
public IStringLocalizer WithCulture(CultureInfo culture) public IStringLocalizer WithCulture(CultureInfo culture)
{ {
return culture == null return culture == null
? new ResourceManagerStringLocalizer(ResourceManager, ResourceAssembly, ResourceBaseName) ? new ResourceManagerStringLocalizer(_resourceManager, _resourceAssemblyWrapper, _resourceBaseName)
: new ResourceManagerWithCultureStringLocalizer( : new ResourceManagerWithCultureStringLocalizer(_resourceManager,
ResourceManager, _resourceAssemblyWrapper,
ResourceAssembly, _resourceBaseName,
ResourceBaseName,
culture); culture);
} }
/// <summary> /// <summary>
/// Gets a resource string from the <see cref="ResourceManager"/> and returns <c>null</c> instead of /// Gets a resource string from the <see cref="_resourceManager"/> and returns <c>null</c> instead of
/// throwing exceptions if a match isn't found. /// throwing exceptions if a match isn't found.
/// </summary> /// </summary>
/// <param name="name">The name of the string resource.</param> /// <param name="name">The name of the string resource.</param>
@ -110,7 +111,7 @@ namespace Microsoft.Framework.Localization
try try
{ {
return culture == null ? ResourceManager.GetString(name) : ResourceManager.GetString(name, culture); return culture == null ? _resourceManager.GetString(name) : _resourceManager.GetString(name, culture);
} }
catch (MissingManifestResourceException) catch (MissingManifestResourceException)
{ {
@ -150,10 +151,7 @@ namespace Microsoft.Framework.Localization
} }
// Internal to allow testing // Internal to allow testing
internal static void ClearResourceNamesCache() internal static void ClearResourceNamesCache() => _resourceNamesCache.Clear();
{
_resourceNamesCache.Clear();
}
private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture) private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture)
{ {
@ -186,19 +184,19 @@ namespace Microsoft.Framework.Localization
private IList<string> GetResourceNamesForCulture(CultureInfo culture) private IList<string> GetResourceNamesForCulture(CultureInfo culture)
{ {
var resourceStreamName = ResourceBaseName; var resourceStreamName = _resourceBaseName;
if (!string.IsNullOrEmpty(culture.Name)) if (!string.IsNullOrEmpty(culture.Name))
{ {
resourceStreamName += "." + culture.Name; resourceStreamName += "." + culture.Name;
} }
resourceStreamName += ".resources"; resourceStreamName += ".resources";
var cacheKey = $"assembly={ResourceAssembly.FullName};resourceStreamName={resourceStreamName}"; var cacheKey = $"assembly={_resourceAssemblyWrapper.FullName};resourceStreamName={resourceStreamName}";
var cultureResourceNames = _resourceNamesCache.GetOrAdd(cacheKey, key => var cultureResourceNames = _resourceNamesCache.GetOrAdd(cacheKey, key =>
{ {
var names = new List<string>(); var names = new List<string>();
using (var cultureResourceStream = ResourceAssembly.GetManifestResourceStream(key)) using (var cultureResourceStream = _resourceAssemblyWrapper.GetManifestResourceStream(key))
using (var resources = new ResourceReader(cultureResourceStream)) using (var resources = new ResourceReader(cultureResourceStream))
{ {
foreach (DictionaryEntry entry in resources) foreach (DictionaryEntry entry in resources)

View File

@ -5,6 +5,7 @@ using System;
using System.Reflection; using System.Reflection;
using System.Resources; using System.Resources;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization.Internal;
using Microsoft.Framework.Runtime; using Microsoft.Framework.Runtime;
namespace Microsoft.Framework.Localization namespace Microsoft.Framework.Localization
@ -34,7 +35,7 @@ namespace Microsoft.Framework.Localization
public IStringLocalizer Create([NotNull] Type resourceSource) public IStringLocalizer Create([NotNull] Type resourceSource)
{ {
var typeInfo = resourceSource.GetTypeInfo(); var typeInfo = resourceSource.GetTypeInfo();
var assembly = typeInfo.Assembly; var assembly = new AssemblyWrapper(typeInfo.Assembly);
var baseName = typeInfo.FullName; var baseName = typeInfo.FullName;
return new ResourceManagerStringLocalizer(new ResourceManager(resourceSource), assembly, baseName); return new ResourceManagerStringLocalizer(new ResourceManager(resourceSource), assembly, baseName);
} }
@ -49,7 +50,10 @@ namespace Microsoft.Framework.Localization
{ {
var assembly = Assembly.Load(new AssemblyName(location ?? _applicationEnvironment.ApplicationName)); var assembly = Assembly.Load(new AssemblyName(location ?? _applicationEnvironment.ApplicationName));
return new ResourceManagerStringLocalizer(new ResourceManager(baseName, assembly), assembly, baseName); return new ResourceManagerStringLocalizer(
new ResourceManager(baseName, assembly),
new AssemblyWrapper(assembly),
baseName);
} }
} }
} }

View File

@ -1,12 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Reflection; using System.Reflection;
using System.Resources; using System.Resources;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization.Internal;
namespace Microsoft.Framework.Localization namespace Microsoft.Framework.Localization
{ {
@ -35,6 +35,19 @@ namespace Microsoft.Framework.Localization
_culture = culture; _culture = culture;
} }
/// <summary>
/// Intended for testing purposes only.
/// </summary>
public ResourceManagerWithCultureStringLocalizer(
[NotNull] ResourceManager resourceManager,
[NotNull] AssemblyWrapper assemblyWrapper,
[NotNull] string baseName,
[NotNull] CultureInfo culture)
: base(resourceManager, assemblyWrapper, baseName)
{
_culture = culture;
}
/// <inheritdoc /> /// <inheritdoc />
public override LocalizedString this[[NotNull] string name] public override LocalizedString this[[NotNull] string name]
{ {

View File

@ -6,7 +6,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Resources; using System.Resources;
using Moq; using Microsoft.Framework.Localization.Internal;
using Xunit; using Xunit;
namespace Microsoft.Framework.Localization.Test namespace Microsoft.Framework.Localization.Test
@ -18,19 +18,11 @@ namespace Microsoft.Framework.Localization.Test
{ {
// Arrange // Arrange
ResourceManagerStringLocalizer.ClearResourceNamesCache(); ResourceManagerStringLocalizer.ClearResourceNamesCache();
var resourceManager = new Mock<ResourceManager>();
var resourceAssembly = new Mock<TestAssembly1>();
resourceAssembly.Setup(rm => rm.GetManifestResourceStream(It.IsAny<string>()))
.Returns(() => MakeResourceStream());
var baseName = "test"; var baseName = "test";
var localizer1 = new ResourceManagerStringLocalizer( var resourceAssembly = new TestAssemblyWrapper();
resourceManager.Object, var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly);
resourceAssembly.Object, var localizer1 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName);
baseName); var localizer2 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName);
var localizer2 = new ResourceManagerStringLocalizer(
resourceManager.Object,
resourceAssembly.Object,
baseName);
// Act // Act
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
@ -41,9 +33,7 @@ namespace Microsoft.Framework.Localization.Test
// Assert // Assert
var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture); var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture);
resourceAssembly.Verify( Assert.Equal(expectedCallCount, resourceAssembly.GetManifestResourceStreamCallCount);
rm => rm.GetManifestResourceStream(It.IsAny<string>()),
Times.Exactly(expectedCallCount));
} }
[Fact] [Fact]
@ -51,24 +41,13 @@ namespace Microsoft.Framework.Localization.Test
{ {
// Arrange // Arrange
ResourceManagerStringLocalizer.ClearResourceNamesCache(); ResourceManagerStringLocalizer.ClearResourceNamesCache();
var resourceManager = new Mock<ResourceManager>();
var resourceAssembly1 = new Mock<TestAssembly1>();
resourceAssembly1.CallBase = true;
var resourceAssembly2 = new Mock<TestAssembly2>();
resourceAssembly2.CallBase = true;
resourceAssembly1.Setup(rm => rm.GetManifestResourceStream(It.IsAny<string>()))
.Returns(() => MakeResourceStream());
resourceAssembly2.Setup(rm => rm.GetManifestResourceStream(It.IsAny<string>()))
.Returns(() => MakeResourceStream());
var baseName = "test"; var baseName = "test";
var localizer1 = new ResourceManagerStringLocalizer( var resourceAssembly1 = new TestAssemblyWrapper("Assembly1");
resourceManager.Object, var resourceAssembly2 = new TestAssemblyWrapper("Assembly2");
resourceAssembly1.Object, var resourceManager1 = new TestResourceManager(baseName, resourceAssembly1.Assembly);
baseName); var resourceManager2 = new TestResourceManager(baseName, resourceAssembly2.Assembly);
var localizer2 = new ResourceManagerStringLocalizer( var localizer1 = new ResourceManagerStringLocalizer(resourceManager1, resourceAssembly1, baseName);
resourceManager.Object, var localizer2 = new ResourceManagerStringLocalizer(resourceManager2, resourceAssembly2, baseName);
resourceAssembly2.Object,
baseName);
// Act // Act
localizer1.ToList(); localizer1.ToList();
@ -76,12 +55,8 @@ namespace Microsoft.Framework.Localization.Test
// Assert // Assert
var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture); var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture);
resourceAssembly1.Verify( Assert.Equal(expectedCallCount, resourceAssembly1.GetManifestResourceStreamCallCount);
rm => rm.GetManifestResourceStream(It.IsAny<string>()), Assert.Equal(expectedCallCount, resourceAssembly2.GetManifestResourceStreamCallCount);
Times.Exactly(expectedCallCount));
resourceAssembly2.Verify(
rm => rm.GetManifestResourceStream(It.IsAny<string>()),
Times.Exactly(expectedCallCount));
} }
private static Stream MakeResourceStream() private static Stream MakeResourceStream()
@ -114,25 +89,35 @@ namespace Microsoft.Framework.Localization.Test
return result; return result;
} }
public class TestAssembly1 : Assembly public class TestResourceManager : ResourceManager
{ {
public override string FullName public TestResourceManager(string baseName, Assembly assembly)
: base(baseName, assembly)
{ {
get
{
return nameof(TestAssembly1);
}
} }
public override string GetString(string name, CultureInfo culture) => null;
} }
public class TestAssembly2 : Assembly public class TestAssemblyWrapper : AssemblyWrapper
{ {
public override string FullName private readonly string _name;
public TestAssemblyWrapper(string name = nameof(TestAssemblyWrapper))
: base(typeof(TestAssemblyWrapper).GetTypeInfo().Assembly)
{ {
get _name = name;
{ }
return nameof(TestAssembly2);
} public int GetManifestResourceStreamCallCount { get; private set; }
public override string FullName => _name;
public override Stream GetManifestResourceStream(string name)
{
GetManifestResourceStreamCallCount++;
return MakeResourceStream();
} }
} }
} }

View File

@ -1,16 +1,17 @@
{ {
"dependencies": { "dependencies": {
"Moq": "4.2.1502.911", "xunit": "2.1.0-*",
"xunit": "2.1.0-*", "xunit.runner.dnx": "2.1.0-*",
"xunit.runner.dnx": "2.1.0-*", "Microsoft.Framework.Localization": "1.0.0-*",
"Microsoft.Framework.Localization": "1.0.0-*" "System.Reflection": "4.0.10-*"
}, },
"commands": { "commands": {
"test": "xunit.runner.dnx" "test": "xunit.runner.dnx"
}, },
"frameworks": { "frameworks": {
"dnx451": { } "dnx451": { },
} "dnxcore50": { }
}
} }