From af28b87660675139964dff597a73fc4a3eea4ccc Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 28 May 2017 11:21:49 -0400 Subject: [PATCH] make unit test easier to extend (#296) --- .../TranslationTests.cs | 15 ++++-- src/StardewModdingAPI/Translation.cs | 47 ++++++++++--------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/StardewModdingAPI.Tests/TranslationTests.cs b/src/StardewModdingAPI.Tests/TranslationTests.cs index 1778ed6a..09f0ce32 100644 --- a/src/StardewModdingAPI.Tests/TranslationTests.cs +++ b/src/StardewModdingAPI.Tests/TranslationTests.cs @@ -19,8 +19,11 @@ namespace StardewModdingAPI.Tests /// A token structure type. public enum TokenType { - /// The tokens are passed in a dictionary. - Dictionary, + /// The tokens are passed in a string/object dictionary. + DictionaryStringObject, + + /// The tokens are passed in a string/string dictionary. + DictionaryStringString, /// The tokens are passed in an anonymous object. AnonymousObject @@ -190,7 +193,7 @@ namespace StardewModdingAPI.Tests ** Translation tokens ****/ [Test(Description = "Assert that multiple translation tokens are replaced correctly regardless of the token structure.")] - public void Translation_Tokens([Values(TokenType.AnonymousObject, TokenType.Dictionary)] TokenType tokenType) + public void Translation_Tokens([Values(TokenType.AnonymousObject, TokenType.DictionaryStringObject, TokenType.DictionaryStringString)] TokenType tokenType) { // arrange string start = Guid.NewGuid().ToString("N"); @@ -207,10 +210,14 @@ namespace StardewModdingAPI.Tests translation = translation.Tokens(new { start, middle, end }); break; - case TokenType.Dictionary: + case TokenType.DictionaryStringObject: translation = translation.Tokens(new Dictionary { ["start"] = start, ["middle"] = middle, ["end"] = end }); break; + case TokenType.DictionaryStringString: + translation = translation.Tokens(new Dictionary { ["start"] = start, ["middle"] = middle, ["end"] = end }); + break; + default: throw new NotSupportedException($"Unknown token type {tokenType}."); } diff --git a/src/StardewModdingAPI/Translation.cs b/src/StardewModdingAPI/Translation.cs index 868ee4fa..8dcaee0f 100644 --- a/src/StardewModdingAPI/Translation.cs +++ b/src/StardewModdingAPI/Translation.cs @@ -1,6 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; +using System.Reflection; using System.Text.RegularExpressions; namespace StardewModdingAPI @@ -82,37 +83,41 @@ namespace StardewModdingAPI } /// Replace tokens in the text like {{value}} with the given values. Returns a new instance. - /// An anonymous object containing token key/value pairs, like new { value = 42, name = "Cranberries" }. + /// An object containing token key/value pairs. This can be an anonymous object (like new { value = 42, name = "Cranberries" }) or a dictionary of token values. /// The argument is null. public Translation Tokens(object tokens) { if (tokens == null) throw new ArgumentNullException(nameof(tokens)); - IDictionary dictionary = tokens - .GetType() - .GetProperties() - .ToDictionary( - p => p.Name, - p => p.GetValue(tokens) - ); - return this.Tokens(dictionary); - } + // get dictionary of tokens + IDictionary tokenLookup = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + { + // from dictionary + if (tokens is IDictionary inputLookup) + { + foreach (DictionaryEntry entry in inputLookup) + { + string key = entry.Key?.ToString().Trim(); + if (key != null) + tokenLookup[key] = entry.Value?.ToString(); + } + } - /// Replace tokens in the text like {{value}} with the given values. Returns a new instance. - /// A dictionary containing token key/value pairs. - /// The argument is null. - public Translation Tokens(IDictionary tokens) - { - if (tokens == null) - throw new ArgumentNullException(nameof(tokens)); + // from object properties + else + { + foreach (PropertyInfo prop in tokens.GetType().GetProperties()) + tokenLookup[prop.Name] = prop.GetValue(tokens)?.ToString(); + } + } - tokens = tokens.ToDictionary(p => p.Key.Trim(), p => p.Value, StringComparer.InvariantCultureIgnoreCase); + // format translation string text = Regex.Replace(this.Text, @"{{([ \w\.\-]+)}}", match => { string key = match.Groups[1].Value.Trim(); - return tokens.TryGetValue(key, out object value) - ? value?.ToString() + return tokenLookup.TryGetValue(key, out string value) + ? value : match.Value; }); return new Translation(this.ModName, this.Locale, this.Key, text);