diff --git a/Fluid.Tests/ColorFiltersTests.cs b/Fluid.Tests/ColorFiltersTests.cs index 896f6c8a..2ee800e9 100644 --- a/Fluid.Tests/ColorFiltersTests.cs +++ b/Fluid.Tests/ColorFiltersTests.cs @@ -1,7 +1,7 @@ using Fluid.Filters; +using Fluid.Tests.Extensions; using Fluid.Values; using System.Globalization; -using System.Linq; using Xunit; namespace Fluid.Tests @@ -188,7 +188,7 @@ public void ColorExtract(string color, object[] arguments, string expected) var context = new TemplateContext(); // Act - var result = ColorFilters.ColorExtract(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.ColorExtract(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToStringValue()); @@ -246,7 +246,7 @@ public void ColorModify(string color, object[] arguments, string expected) var context = new TemplateContext(); // Act - var result = ColorFilters.ColorModify(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.ColorModify(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToStringValue()); @@ -304,7 +304,7 @@ public void ColorSaturate(string color, object[] arguments, string expected) var context = new TemplateContext(); // Act - var result = ColorFilters.ColorSaturate(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.ColorSaturate(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToStringValue()); @@ -321,7 +321,7 @@ public void ColorDesaturate(string color, object[] arguments, string expected) var context = new TemplateContext(); // Act - var result = ColorFilters.ColorDesaturate(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.ColorDesaturate(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToStringValue()); @@ -338,7 +338,7 @@ public void ColorLighten(string color, object[] arguments, string expected) var context = new TemplateContext(); // Act - var result = ColorFilters.ColorLighten(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.ColorLighten(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToStringValue()); @@ -355,7 +355,7 @@ public void ColorDarken(string color, object[] arguments, string expected) var context = new TemplateContext(); // Act - var result = ColorFilters.ColorDarken(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.ColorDarken(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToStringValue()); @@ -372,7 +372,7 @@ public void ColorDifference(string color, object[] arguments, decimal expected) var context = new TemplateContext(); // Act - var result = ColorFilters.GetColorDifference(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.GetColorDifference(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToNumberValue()); @@ -389,7 +389,7 @@ public void BrightnessDifference(string color, object[] arguments, decimal expec var context = new TemplateContext(); // Act - var result = ColorFilters.GetColorBrightnessDifference(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.GetColorBrightnessDifference(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToNumberValue()); @@ -406,7 +406,7 @@ public void ColorContrast(string color, object[] arguments, decimal expected) var context = new TemplateContext(); // Act - var result = ColorFilters.GetColorContrast(input, new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), context); + var result = ColorFilters.GetColorContrast(input, arguments.ToFilterArguments(), context); // Assert Assert.Equal(expected, result.Result.ToNumberValue()); diff --git a/Fluid.Tests/Extensions/ConversionExtensions.cs b/Fluid.Tests/Extensions/ConversionExtensions.cs new file mode 100644 index 00000000..d96002fb --- /dev/null +++ b/Fluid.Tests/Extensions/ConversionExtensions.cs @@ -0,0 +1,13 @@ +using Fluid.Values; +using System.Linq; + +namespace Fluid.Tests.Extensions +{ + internal static class ConversionExtensions + { + public static FilterArguments ToFilterArguments(this object[] arguments) + { + return new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()); + } + } +} diff --git a/Fluid.Tests/Integration/StandardFilterTests.cs b/Fluid.Tests/Integration/StandardFilterTests.cs index fe7fde9d..39c8c1fe 100644 --- a/Fluid.Tests/Integration/StandardFilterTests.cs +++ b/Fluid.Tests/Integration/StandardFilterTests.cs @@ -1,7 +1,7 @@ using Fluid.Filters; +using Fluid.Tests.Extensions; using Fluid.Values; using System; -using System.Linq; using System.Threading.Tasks; using Xunit; @@ -50,7 +50,7 @@ public void TestUpcase(string expected, object input) [InlineData("oob", "foobar", "1", "3")] public void TestSlice(string expected, object input, params object[] arguments) { - Assert.Equal(expected, StringFilters.Slice(FluidValue.Create(input, TemplateOptions.Default), new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), new TemplateContext()).Result.ToObjectValue()); + Assert.Equal(expected, StringFilters.Slice(FluidValue.Create(input, TemplateOptions.Default), arguments.ToFilterArguments(), new TemplateContext()).Result.ToObjectValue()); } [Theory] @@ -58,7 +58,7 @@ public void TestSlice(string expected, object input, params object[] arguments) [InlineData("foobar", 0, "")] public void TestSliceArgument(object input, params object[] arguments) { - Assert.Throws(() => StringFilters.Slice(FluidValue.Create(input, TemplateOptions.Default), new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), new TemplateContext()).Result.ToObjectValue()); + Assert.Throws(() => StringFilters.Slice(FluidValue.Create(input, TemplateOptions.Default), arguments.ToFilterArguments(), new TemplateContext()).Result.ToObjectValue()); } [Theory] @@ -76,7 +76,7 @@ public void TestSliceOnArrays(string expected, params object[] arguments) { var foobar = new object [] { 'f', 'o', 'o', 'b', 'a', 'r' }; - var result = StringFilters.Slice(FluidValue.Create(foobar, TemplateOptions.Default), new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()), new TemplateContext()); + var result = StringFilters.Slice(FluidValue.Create(foobar, TemplateOptions.Default), arguments.ToFilterArguments(), new TemplateContext()); Assert.IsType(result.Result); string resultString = ""; diff --git a/Fluid.Tests/StringFiltersTests.cs b/Fluid.Tests/StringFiltersTests.cs index 6f91a9c1..d64a6814 100644 --- a/Fluid.Tests/StringFiltersTests.cs +++ b/Fluid.Tests/StringFiltersTests.cs @@ -2,6 +2,7 @@ using Fluid.Values; using Fluid.Filters; using Xunit; +using Fluid.Tests.Extensions; namespace Fluid.Tests { @@ -126,30 +127,32 @@ public void Prepend() Assert.Equal("Hello World", result.Result.ToStringValue()); } - [Fact] - public void RemoveFirst() + [Theory] + [InlineData("a b a a", new object[] { "a " }, "b a a")] + [InlineData("1 1 1 1", new object[] { 1 }, " 1 1 1")] + public void RemoveFirst(string input, object[] arguments, string expected) { - var input = new StringValue("abcabc"); - - var arguments = new FilterArguments().Add(new StringValue("b")); + var filterInput = new StringValue(input); + var filterArguments = arguments.ToFilterArguments(); var context = new TemplateContext(); - var result = StringFilters.RemoveFirst(input, arguments, context); + var result = StringFilters.RemoveFirst(filterInput, filterArguments, context); - Assert.Equal("acabc", result.Result.ToStringValue()); + Assert.Equal(expected, result.Result.ToStringValue()); } - [Fact] - public void Remove() + [Theory] + [InlineData("a a a a", new object[] { "a" }, " ")] + [InlineData("1 1 1 1", new object[] { 1 }, " ")] + public void Remove(string input, object[] arguments, string expected) { - var input = new StringValue("abcabc"); - - var arguments = new FilterArguments().Add(new StringValue("b")); + var filterInput = new StringValue(input); + var filterArguments = arguments.ToFilterArguments(); var context = new TemplateContext(); - var result = StringFilters.Remove(input, arguments, context); + var result = StringFilters.Remove(filterInput, filterArguments, context); - Assert.Equal("acac", result.Result.ToStringValue()); + Assert.Equal(expected, result.Result.ToStringValue()); } [Fact] @@ -161,36 +164,76 @@ public void RemovesReturnsInputWhenArgumentIsEmpty() var context = new TemplateContext(); var result = StringFilters.Remove(input, arguments, context); + + Assert.Equal("abcabc", result.Result.ToStringValue()); } - [Fact] - public void ReplaceFirst() + [Theory] + [InlineData("a a b a", new object[] { " a" }, "a a b")] + [InlineData("1 1 1 1", new object[] { 1 }, "1 1 1 ")] + public void RemoveLast(string input, object[] arguments, string expected) { - var input = new StringValue("abcabc"); - - var arguments = new FilterArguments().Add(new StringValue("b")).Add(new StringValue("B")); + var filterInput = new StringValue(input); + var filterArguments = arguments.ToFilterArguments(); var context = new TemplateContext(); - var result = StringFilters.ReplaceFirst(input, arguments, context); + var result = StringFilters.RemoveLast(filterInput, filterArguments, context); - Assert.Equal("aBcabc", result.Result.ToStringValue()); + Assert.Equal(expected, result.Result.ToStringValue()); } - [Fact] - public void Replace() + [Theory] + [InlineData("a a a a", new object[] { "a", "b" }, "b a a a")] + [InlineData("1 1 1 1", new object[] { 1, 2 }, "2 1 1 1")] + [InlineData("1 1 1 1", new object[] { 2, 3 }, "1 1 1 1")] + [InlineData("1 1 1 1", new object[] { "1", 2 }, "2 1 1 1")] + [InlineData("aa bb cc aa bb cc", new object[] { "cc", "dd" }, "aa bb dd aa bb cc")] + public void ReplaceFirst(string input, object[] arguments, string expected) { - var input = new StringValue("abcabc"); + var filterInput = new StringValue(input); + var filterArguments = arguments.ToFilterArguments(); + var context = new TemplateContext(); - var arguments = new FilterArguments().Add(new StringValue("b")).Add(new StringValue("B")); + var result = StringFilters.ReplaceFirst(filterInput, filterArguments, context); + + Assert.Equal(expected, result.Result.ToStringValue()); + } + + [Theory] + [InlineData("a a a a", new object[] { "a", "b" }, "b b b b")] + [InlineData("1 1 1 1", new object[] { 1, 2 }, "2 2 2 2")] + [InlineData("1 1 1 1", new object[] { 2, 3 }, "1 1 1 1")] + [InlineData("1 1 1 1", new object[] { "1", 2 }, "2 2 2 2")] + [InlineData("aa bb cc aa bb cc", new object[] { "cc", "dd" }, "aa bb dd aa bb dd")] + public void Replace(string input, object[] arguments, string expected) + { + var filterInput = new StringValue(input); + var filterArguments = arguments.ToFilterArguments(); var context = new TemplateContext(); - var result = StringFilters.Replace(input, arguments, context); + var result = StringFilters.Replace(filterInput, filterArguments, context); - Assert.Equal("aBcaBc", result.Result.ToStringValue()); + Assert.Equal(expected, result.Result.ToStringValue()); } [Theory] + [InlineData("a a a a", new object[] { "a", "b" }, "a a a b")] + [InlineData("1 1 1 1", new object[] { 1, 2 }, "1 1 1 2")] + [InlineData("1 1 1 1", new object[] { 2, 3 }, "1 1 1 1")] + [InlineData("1 1 1 1", new object[] { "1", 2 }, "1 1 1 2")] + [InlineData("aa bb cc aa bb cc", new object[] { "cc", "dd" }, "aa bb cc aa bb dd")] + public void ReplaceLast(string input, object[] arguments, string expected) + { + var filterInput = new StringValue(input); + var filterArguments = arguments.ToFilterArguments(); + var context = new TemplateContext(); + + var result = StringFilters.ReplaceLast(filterInput, filterArguments, context); + Assert.Equal(expected, result.Result.ToStringValue()); + } + + [Theory] [InlineData("hello", new object[] { 0 }, "h")] [InlineData("hello", new object[] { 1 }, "e")] [InlineData("hello", new object[] { 1, 3 }, "ell")] @@ -200,7 +243,7 @@ public void Replace() public void Slice(object input, object[] arguments, string expected) { var filterInput = FluidValue.Create(input, TemplateOptions.Default); - var filterArguments = new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()); + var filterArguments = arguments.ToFilterArguments(); var context = new TemplateContext(); var result = StringFilters.Slice(filterInput, filterArguments, context); @@ -222,7 +265,7 @@ public void Slice(object input, object[] arguments, string expected) public void SliceOutsideBounds(object input, object[] arguments, string expected) { var filterInput = FluidValue.Create(input, TemplateOptions.Default); - var filterArguments = new FilterArguments(arguments.Select(x => FluidValue.Create(x, TemplateOptions.Default)).ToArray()); + var filterArguments = arguments.ToFilterArguments(); var context = new TemplateContext(); var result = StringFilters.Slice(filterInput, filterArguments, context); diff --git a/Fluid/Filters/StringFilters.cs b/Fluid/Filters/StringFilters.cs index 5f22d7c3..bd5d5967 100644 --- a/Fluid/Filters/StringFilters.cs +++ b/Fluid/Filters/StringFilters.cs @@ -22,8 +22,10 @@ public static FilterCollection WithStringFilters(this FilterCollection filters) filters.AddFilter("prepend", Prepend); filters.AddFilter("remove_first", RemoveFirst); filters.AddFilter("remove", Remove); + filters.AddFilter("remove_last", RemoveLast); filters.AddFilter("replace_first", ReplaceFirst); filters.AddFilter("replace", Replace); + filters.AddFilter("replace_last", ReplaceLast); filters.AddFilter("slice", Slice); filters.AddFilter("split", Split); filters.AddFilter("strip", Strip); @@ -108,6 +110,21 @@ public static ValueTask Remove(FluidValue input, FilterArguments arg return new StringValue(input.ToStringValue().Replace(argument, "")); } + public static ValueTask RemoveLast(FluidValue input, FilterArguments arguments, TemplateContext context) + { + var remove = arguments.At(0).ToStringValue(); + var value = input.ToStringValue(); + + var index = value.LastIndexOf(remove); + + if (index != -1) + { + return new StringValue(value.Remove(index, remove.Length)); + } + + return input; + } + public static ValueTask ReplaceFirst(FluidValue input, FilterArguments arguments, TemplateContext context) { string remove = arguments.At(0).ToStringValue(); @@ -128,6 +145,21 @@ public static ValueTask Replace(FluidValue input, FilterArguments ar return new StringValue(input.ToStringValue().Replace(arguments.At(0).ToStringValue(), arguments.At(1).ToStringValue())); } + public static ValueTask ReplaceLast(FluidValue input, FilterArguments arguments, TemplateContext context) + { + var remove = arguments.At(0).ToStringValue(); + var value = input.ToStringValue(); + + var index = value.LastIndexOf(remove); + + if (index != -1) + { + return new StringValue(value.Substring(0, index) + arguments.At(1).ToStringValue() + value.Substring(index + remove.Length)); + } + + return input; + } + public static ValueTask Slice(FluidValue input, FilterArguments arguments, TemplateContext context) { var firstArgument = arguments.At(0);