diff --git a/src/SmartFormat.Tests/Extensions/DefaultSourceTests.cs b/src/SmartFormat.Tests/Extensions/DefaultSourceTests.cs index ff2ee0e5..913524dd 100644 --- a/src/SmartFormat.Tests/Extensions/DefaultSourceTests.cs +++ b/src/SmartFormat.Tests/Extensions/DefaultSourceTests.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using FluentAssertions.Formatting; using NUnit.Framework; using SmartFormat.Core.Extensions; +using SmartFormat.Core.Formatting; using SmartFormat.Extensions; using SmartFormat.Tests.TestUtils; @@ -9,21 +11,29 @@ namespace SmartFormat.Tests.Extensions [TestFixture] public class DefaultSourceTests { - private class SourceImplementation : Source - { } + private static SmartFormatter GetFormatter() + { + var smart = new SmartFormatter(); + smart.AddExtensions(new DefaultSource()); + smart.AddExtensions(new DefaultFormatter()); + return smart; + } [Test] - public void Call_With_NonNumeric_Argument_Should_Fail() + public void Call_With_NonNumeric_Placeholder_Should_Fail() { - var source = new DefaultSource(); - Assert.That(source.TryEvaluateSelector(FormattingInfoExtensions.Create("{a}", new List())), Is.EqualTo(false)); + var smart = GetFormatter(); + Assert.That(code: () => smart.Format("{a}", 0), + Throws.TypeOf().And.Message.Contains("No source extension")); } [Test] - public void TryEvaluateSelector_Should_Fail() + public void Call_With_Numeric_Placeholder_Should_Succeed() { - var source = new SourceImplementation(); - Assert.That(source.TryEvaluateSelector(FormattingInfoExtensions.Create("{Dummy}", new List())), Is.EqualTo(false)); + var smart = GetFormatter(); + var result = string.Empty; + Assert.That(code:() => { result = smart.Format("{0}", 999); }, Throws.Nothing); + Assert.That(result, Is.EqualTo("999")); } } } diff --git a/src/SmartFormat.Tests/Extensions/KeyValuePairSourceTests.cs b/src/SmartFormat.Tests/Extensions/KeyValuePairSourceTests.cs new file mode 100644 index 00000000..71d81a4a --- /dev/null +++ b/src/SmartFormat.Tests/Extensions/KeyValuePairSourceTests.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using NUnit.Framework; +using SmartFormat.Core.Formatting; +using SmartFormat.Extensions; + +namespace SmartFormat.Tests.Extensions +{ + [TestFixture] + public class KeyValuePairSourceTests + { + private SmartFormatter GetFormatter() + { + var smart = new SmartFormatter(); + smart.AddExtensions(new KeyValuePairSource()); + smart.AddExtensions(new DefaultFormatter()); + return smart; + } + + [Test] + public void Call_With_Null_Should_Fail() + { + var smart = GetFormatter(); + Assert.That(code: () => smart.Format("{a}", null, null), + Throws.TypeOf().And.Message.Contains("No source extension")); + } + + [Test] + public void Call_With_Unknown_Type_Should_Fail() + { + var smart = GetFormatter(); + // only KeyValuePair can be used + Assert.That(code: () => smart.Format("{a}", new KeyValuePair("a", 123)), + Throws.TypeOf().And.Message.Contains("No source extension")); + } + + [TestCase("my value", "my value")] + [TestCase(null, "")] + public void Call_With_KeyValuePair_Should_Succeed(string? theValue, string expected) + { + var smart = GetFormatter(); + var result = string.Empty; + Assert.That( + code: () => + { + result = smart.Format("{placeholder}", new KeyValuePair("placeholder", theValue)); + }, Throws.Nothing); + Assert.That(result, Is.EqualTo(expected)); + } + } +} diff --git a/src/SmartFormat.Tests/SmartFormat.Tests.csproj b/src/SmartFormat.Tests/SmartFormat.Tests.csproj index 905496e1..12dc0a39 100644 --- a/src/SmartFormat.Tests/SmartFormat.Tests.csproj +++ b/src/SmartFormat.Tests/SmartFormat.Tests.csproj @@ -20,8 +20,8 @@ - - + + diff --git a/src/SmartFormat/Extensions/KeyValuePairSource.cs b/src/SmartFormat/Extensions/KeyValuePairSource.cs new file mode 100644 index 00000000..0377ffc2 --- /dev/null +++ b/src/SmartFormat/Extensions/KeyValuePairSource.cs @@ -0,0 +1,38 @@ +// +// Copyright (C) axuno gGmbH, Scott Rippey, Bernhard Millauer and other contributors. +// Licensed under the MIT license. +// + +using System; +using System.Collections.Generic; +using SmartFormat.Core.Extensions; +using SmartFormat.Core.Parsing; + +namespace SmartFormat.Extensions +{ + /// + /// Class to evaluate a with . + /// The key must be , the value must be a . + /// + /// + /// Smart.Format("{key}", new KeyValuePair<string, object?>("key", "a value"); + /// Result: "a value". + /// + public class KeyValuePairSource : Source + { + /// + public override bool TryEvaluateSelector(ISelectorInfo selectorInfo) + { + switch (selectorInfo.CurrentValue) + { + case null: + return false; + case KeyValuePair kvp when kvp.Key == selectorInfo.SelectorText: + selectorInfo.Result = kvp.Value; + return true; + default: + return false; + } + } + } +} diff --git a/src/SmartFormat/Extensions/WellKnownExtensionTypes.cs b/src/SmartFormat/Extensions/WellKnownExtensionTypes.cs index 17a4562e..48b30358 100644 --- a/src/SmartFormat/Extensions/WellKnownExtensionTypes.cs +++ b/src/SmartFormat/Extensions/WellKnownExtensionTypes.cs @@ -35,7 +35,8 @@ public static class WellKnownExtensionTypes { "SmartFormat.Extensions.XmlSource", 9000 }, // sources for specific types must be in the list before ReflectionSource { "SmartFormat.Extensions.ReflectionSource", 10000 }, - { "SmartFormat.Extensions.DefaultSource", 11000 } + { "SmartFormat.Extensions.DefaultSource", 11000 }, + { "SmartFormat.Extensions.KeyValuePairSource", 12000 } }; /// diff --git a/src/SmartFormat/Smart.cs b/src/SmartFormat/Smart.cs index e8a9afe0..2b3eba5f 100644 --- a/src/SmartFormat/Smart.cs +++ b/src/SmartFormat/Smart.cs @@ -114,7 +114,7 @@ public static string Format(string format, object? arg0) /// /// s: /// , , , - /// , , . + /// , , , /// /// /// s: @@ -136,7 +136,8 @@ public static SmartFormatter CreateDefaultSmartFormat(SmartSettings? settings = new ValueTupleSource(), new ReflectionSource(), // for string.Format behavior - new DefaultSource() + new DefaultSource(), + new KeyValuePairSource() ) .AddExtensions( new PluralLocalizationFormatter(), diff --git a/src/SmartFormat/SmartFormatter.cs b/src/SmartFormat/SmartFormatter.cs index 0544cf7a..7fec430e 100644 --- a/src/SmartFormat/SmartFormatter.cs +++ b/src/SmartFormat/SmartFormatter.cs @@ -387,6 +387,8 @@ public void Format(FormattingInfo formattingInfo) var childFormattingInfo = formattingInfo.CreateChild(placeholder); try { + // Note: If there is no selector (like {:0.00}), + // FormattingInfo.CurrentValue is left unchanged EvaluateSelectors(childFormattingInfo); } catch (Exception ex)