Skip to content

Commit

Permalink
LuaScript: use invariant regex on parameter parsing (fixes #2350)
Browse files Browse the repository at this point in the history
This changes the regex to use RegexOptions.CultureInvariant and adds an easy way to do tests like this in the future with `[Fact, TestCulture("tr-TR")]` for example, which will set and restore the culture for a specific test.
  • Loading branch information
NickCraver committed Jan 22, 2023
1 parent 757169b commit 31bd60f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/StackExchange.Redis/ScriptParameterMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public ScriptParameters(RedisKey[] keys, RedisValue[] args)
}
}

private static readonly Regex ParameterExtractor = new Regex(@"@(?<paramName> ([a-z]|_) ([a-z]|_|\d)*)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex ParameterExtractor = new Regex(@"@(?<paramName> ([a-z]|_) ([a-z]|_|\d)*)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);

private static string[] ExtractParameters(string script)
{
Expand Down
47 changes: 47 additions & 0 deletions tests/StackExchange.Redis.Tests/Helpers/Attributes.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
Expand Down Expand Up @@ -184,3 +186,48 @@ public static RunSummary Update(this RunSummary summary, SkippableMessageBus bus
return summary;
}
}

/// <summary>
/// Supports changing culture for the duration of a single test.
/// <see cref="Thread.CurrentThread" /> and <see cref="CultureInfo.CurrentCulture" /> with another culture.
/// </summary>
/// <remarks>
/// Based on: https://bartwullems.blogspot.com/2022/03/xunit-change-culture-during-your-test.html
/// </remarks>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class TestCultureAttribute : BeforeAfterTestAttribute
{
private readonly CultureInfo culture;
private CultureInfo? originalCulture;

/// <summary>
/// Replaces the culture and UI culture of the current thread with <paramref name="culture" />.
/// </summary>
/// <param name="culture">The name of the culture.</param>
public TestCultureAttribute(string culture) => this.culture = new CultureInfo(culture, false);

/// <summary>
/// Stores the current <see cref="Thread.CurrentPrincipal" /> and <see cref="CultureInfo.CurrentCulture" />
/// and replaces them with the new cultures defined in the constructor.
/// </summary>
/// <param name="methodUnderTest">The method under test</param>
public override void Before(MethodInfo methodUnderTest)
{
originalCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = culture;
CultureInfo.CurrentCulture.ClearCachedData();
}

/// <summary>
/// Restores the original <see cref="CultureInfo.CurrentCulture" /> to <see cref="Thread.CurrentPrincipal" />.
/// </summary>
/// <param name="methodUnderTest">The method under test</param>
public override void After(MethodInfo methodUnderTest)
{
if (originalCulture is not null)
{
Thread.CurrentThread.CurrentCulture = originalCulture;
CultureInfo.CurrentCulture.ClearCachedData();
}
}
}
23 changes: 23 additions & 0 deletions tests/StackExchange.Redis.Tests/ScriptingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,29 @@ public async Task TestEvalShaReadOnlyAsync()
Assert.Equal("bar", result.ToString());
}

[Fact, TestCulture("en-US")]
public void LuaScriptEnglishParameters() => LuaScriptParameterShared();

[Fact, TestCulture("tr-TR")]
public void LuaScriptTurkishParameters() => LuaScriptParameterShared();

private void LuaScriptParameterShared()
{
const string Script = "redis.call('set', @key, @testIId)";
var prepared = LuaScript.Prepare(Script);
var key = Me();
var p = new { key = (RedisKey)key, testIId = "hello" };

prepared.ExtractParameters(p, null, out RedisKey[]? keys, out RedisValue[]? args);
Assert.NotNull(keys);
Assert.Single(keys);
Assert.Equal(key, keys[0]);
Assert.NotNull(args);
Assert.Equal(2, args.Length);
Assert.Equal(key, args[0]);
Assert.Equal("hello", args[1]);
}

private static void TestNullValue(RedisResult? value)
{
Assert.True(value == null || value.IsNull);
Expand Down

0 comments on commit 31bd60f

Please sign in to comment.