Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions src/SmartFormat.Tests/Extensions/DefaultSourceTests.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<object?>())), Is.EqualTo(false));
var smart = GetFormatter();
Assert.That(code: () => smart.Format("{a}", 0),
Throws.TypeOf<FormattingException>().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<object?>())), 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"));
}
}
}
50 changes: 50 additions & 0 deletions src/SmartFormat.Tests/Extensions/KeyValuePairSourceTests.cs
Original file line number Diff line number Diff line change
@@ -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<FormattingException>().And.Message.Contains("No source extension"));
}

[Test]
public void Call_With_Unknown_Type_Should_Fail()
{
var smart = GetFormatter();
// only KeyValuePair<string, object?> can be used
Assert.That(code: () => smart.Format("{a}", new KeyValuePair<string, int>("a", 123)),
Throws.TypeOf<FormattingException>().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<string, object?>("placeholder", theValue));
}, Throws.Nothing);
Assert.That(result, Is.EqualTo(expected));
}
}
}
4 changes: 2 additions & 2 deletions src/SmartFormat.Tests/SmartFormat.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="FluentAssertions" Version="6.2.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="FluentAssertions" Version="6.5.1" />
</ItemGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
38 changes: 38 additions & 0 deletions src/SmartFormat/Extensions/KeyValuePairSource.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Class to evaluate a <see cref="Selector"/> with <see cref="KeyValuePair{TKey,TValue}"/>.
/// The key must be <see langword="string"/>, the value must be a <see cref="Nullable{T}"/> <see cref="object"/>.
/// </summary>
/// <example>
/// Smart.Format("{key}", new KeyValuePair&lt;string, object?&gt;("key", "a value");
/// Result: "a value".
/// </example>
public class KeyValuePairSource : Source
{
/// <inheritdoc />
public override bool TryEvaluateSelector(ISelectorInfo selectorInfo)
{
switch (selectorInfo.CurrentValue)
{
case null:
return false;
case KeyValuePair<string, object?> kvp when kvp.Key == selectorInfo.SelectorText:
selectorInfo.Result = kvp.Value;
return true;
default:
return false;
}
}
}
}
3 changes: 2 additions & 1 deletion src/SmartFormat/Extensions/WellKnownExtensionTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
};

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions src/SmartFormat/Smart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public static string Format(string format, object? arg0)
/// <para>
/// <see cref="ISource"/>s:
/// <see cref="StringSource"/>, <see cref="ListFormatter"/>, <see cref="DictionarySource"/>,
/// <see cref="ValueTupleSource"/>, <see cref="ReflectionSource"/>, <see cref="DefaultSource"/>.
/// <see cref="ValueTupleSource"/>, <see cref="ReflectionSource"/>, <see cref="DefaultSource"/>, <see cref="KeyValuePairSource"/>
/// </para>
/// <para>
/// <see cref="IFormatter"/>s:
Expand All @@ -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(),
Expand Down
2 changes: 2 additions & 0 deletions src/SmartFormat/SmartFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down