From 588ef30b31e7f5092b5ad8aa5c5ef1d9f56667b5 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 11 May 2024 14:29:33 +0200 Subject: [PATCH] Add String.Equals with StringComparison (#93) --- .../Parsers/ArgumentsParser.cs | 4 +- .../Utils/EnumUtils.cs | 35 + .../Helpers/MathHelpers.cs | 6 +- .../Helpers/StringHelpers.cs | 887 +++++++++--------- .../Helpers/StringHelpersTests.cs | 44 +- .../Templates/StringHelpersTemplateTests.cs | 38 + 6 files changed, 568 insertions(+), 446 deletions(-) create mode 100644 src/Handlebars.Net.Helpers.Core/Utils/EnumUtils.cs diff --git a/src/Handlebars.Net.Helpers.Core/Parsers/ArgumentsParser.cs b/src/Handlebars.Net.Helpers.Core/Parsers/ArgumentsParser.cs index d2bdbf5..1b9fcf0 100644 --- a/src/Handlebars.Net.Helpers.Core/Parsers/ArgumentsParser.cs +++ b/src/Handlebars.Net.Helpers.Core/Parsers/ArgumentsParser.cs @@ -45,9 +45,9 @@ public static class ArgumentsParser return argument; } - public static object ParseAsIntLongOrDouble(IHandlebars context, object value) + public static object ParseAsIntLongOrDouble(IHandlebars context, object? value) { - var parsedValue = StringValueParser.Parse(context, value as string ?? value.ToString() ?? string.Empty); + var parsedValue = StringValueParser.Parse(context, value as string ?? value?.ToString() ?? string.Empty); if (SupportedTypes.Contains(parsedValue.GetType())) { diff --git a/src/Handlebars.Net.Helpers.Core/Utils/EnumUtils.cs b/src/Handlebars.Net.Helpers.Core/Utils/EnumUtils.cs new file mode 100644 index 0000000..bdb721c --- /dev/null +++ b/src/Handlebars.Net.Helpers.Core/Utils/EnumUtils.cs @@ -0,0 +1,35 @@ +using System.Diagnostics.CodeAnalysis; + +namespace HandlebarsDotNet.Helpers.Utils; + +public static class EnumUtils +{ + public static bool TryParse(object? value, [NotNullWhen(true)] out TEnum? comparisonType) where TEnum : struct, Enum + { + switch (value) + { + case TEnum valueAsEnum: + comparisonType = valueAsEnum; + return true; + + case int valueAsInt when Enum.IsDefined(typeof(TEnum), valueAsInt): + comparisonType = IntToEnum(valueAsInt); + return true; + + case string stringValue when Enum.TryParse(stringValue, out var parsedAsEnum): + comparisonType = parsedAsEnum; + return true; + + case string stringValue when int.TryParse(stringValue, out var parsedAsInt) && Enum.IsDefined(typeof(TEnum), parsedAsInt): + comparisonType = IntToEnum(parsedAsInt); + return true; + + default: + comparisonType = default; + return false; + } + } + + public static TEnum IntToEnum(int value) where TEnum : struct, Enum + => (TEnum)Enum.ToObject(typeof(TEnum), value); +} \ No newline at end of file diff --git a/src/Handlebars.Net.Helpers/Helpers/MathHelpers.cs b/src/Handlebars.Net.Helpers/Helpers/MathHelpers.cs index 6288a99..65ce11a 100644 --- a/src/Handlebars.Net.Helpers/Helpers/MathHelpers.cs +++ b/src/Handlebars.Net.Helpers/Helpers/MathHelpers.cs @@ -7,6 +7,8 @@ namespace HandlebarsDotNet.Helpers.Helpers; internal class MathHelpers : BaseHelpers, IHelpers { + private const double Tolerance = 1e-20; // 20 Digits of precision + [HandlebarsWriter(WriterType.Value)] public object Add(object value1, object value2) { @@ -40,7 +42,7 @@ public double Divide(object value1, object value2) [HandlebarsWriter(WriterType.Value)] public bool Equal(object value1, object value2) { - return ExecuteUtils.Execute(Context, value1, value2, (x1, x2) => x1 == x2, (x1, x2) => x1 == x2, (x1, x2) => x1 == x2); + return ExecuteUtils.Execute(Context, value1, value2, (x1, x2) => x1 == x2, (x1, x2) => x1 == x2, (x1, x2) => Math.Abs(x1 - x2) < Tolerance); } [HandlebarsWriter(WriterType.Value)] @@ -106,7 +108,7 @@ public object Multiply(object value1, object value2) [HandlebarsWriter(WriterType.Value)] public bool NotEqual(object value1, object value2) { - return ExecuteUtils.Execute(Context, value1, value2, (x1, x2) => x1 != x2, (x1, x2) => x1 != x2, (x1, x2) => x1 != x2); + return ExecuteUtils.Execute(Context, value1, value2, (x1, x2) => x1 != x2, (x1, x2) => x1 != x2, (x1, x2) => Math.Abs(x1 - x2) > Tolerance); } [HandlebarsWriter(WriterType.Value)] diff --git a/src/Handlebars.Net.Helpers/Helpers/StringHelpers.cs b/src/Handlebars.Net.Helpers/Helpers/StringHelpers.cs index c8c7833..835fa78 100644 --- a/src/Handlebars.Net.Helpers/Helpers/StringHelpers.cs +++ b/src/Handlebars.Net.Helpers/Helpers/StringHelpers.cs @@ -1,438 +1,451 @@ -using System; -using System.Collections; -using System.Linq; -using System.Text; -using HandlebarsDotNet.Helpers.Attributes; -using HandlebarsDotNet.Helpers.Enums; -using HandlebarsDotNet.Helpers.Models; -using Stef.Validation; - -namespace HandlebarsDotNet.Helpers.Helpers; - -/// -/// Some code copied from https://www.30secondsofcode.org/c-sharp/t/string/p/1 -/// and based on https://github.com/helpers/handlebars-helpers#string -/// -internal class StringHelpers : BaseHelpers, IHelpers -{ - [HandlebarsWriter(WriterType.String)] - public string Append(string value, string append) - { - if (string.IsNullOrEmpty(value)) - { - return append; - } - - if (string.IsNullOrEmpty(append)) - { - return value; - } - - return value + append; - } - - [HandlebarsWriter(WriterType.String)] - public static string Base64Decode(string value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - var base64EncodedBytes = Convert.FromBase64String(value); - return Encoding.UTF8.GetString(base64EncodedBytes); - } - - [HandlebarsWriter(WriterType.String)] - public static string Base64Encode(string value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - var plainTextBytes = Encoding.UTF8.GetBytes(value); - return Convert.ToBase64String(plainTextBytes); - } - - [HandlebarsWriter(WriterType.String)] - public string Camelcase(string value) - { - if (string.IsNullOrEmpty(value) || value.Length < 2) - { - return value; - } - - string[] words = value.Split(new char[] { }, StringSplitOptions.RemoveEmptyEntries); - - var builder = new StringBuilder(words[0].ToLower()); - for (int i = 1; i < words.Length; i++) - { - builder.Append(words[i].Substring(0, 1).ToUpper()); - builder.Append(words[i].Substring(1)); - } - - return builder.ToString(); - } - - [HandlebarsWriter(WriterType.String)] - public string Capitalize(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - char[] chars = value.ToCharArray(); - chars[0] = char.ToUpper(chars[0]); - return new string(chars); - } - - [HandlebarsWriter(WriterType.Value)] - public object? Coalesce(params object?[] arguments) - { - foreach (var arg in arguments.Where(a => a is { } and not UndefinedBindingResult)) - { - if (arg is string stringValue) - { - if (!string.IsNullOrWhiteSpace(stringValue)) - { - return stringValue; - } - } - else - { - return arg; - } - } - - return null; - } - - [HandlebarsWriter(WriterType.String)] - public string Concat(string value, string append) - { - return Append(value, append); - } - - [HandlebarsWriter(WriterType.Value)] - public bool Contains(string value, string test) - { - Guard.NotNull(value); - - return value.Contains(test); - } - - [HandlebarsWriter(WriterType.String)] - public string Ellipsis(string value, int length) - { - Guard.Condition(length, l => l >= 0); - - if (string.IsNullOrEmpty(value) || value.Length <= length) - { - return value; - } - - return value.Substring(0, length) + "..."; - } - - [HandlebarsWriter(WriterType.Value)] - public bool IsString(object value) - { - return value is string; - } - - [HandlebarsWriter(WriterType.String)] - public string Join(IEnumerable values, string? separator = null) - { - if (values == null) - { - throw new ArgumentNullException(nameof(values)); - } - - return string.Join(separator ?? string.Empty, values.Cast()); - } - - [HandlebarsWriter(WriterType.String)] - public string Lowercase(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return value.ToLower(); - } - - [HandlebarsWriter(WriterType.String)] - public string PadLeft(string value, int totalWidth, string padChar) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - return padChar?.Length > 0 ? value.PadLeft(totalWidth, padChar[0]) : value.PadLeft(totalWidth); - } - - [HandlebarsWriter(WriterType.String)] - public string PadRight(string value, int totalWidth, string padChar) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - return padChar?.Length > 0 ? value.PadRight(totalWidth, padChar[0]) : value.PadRight(totalWidth); - } - - [HandlebarsWriter(WriterType.String)] - public string Pascalcase(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - if (value.Length < 2) - { - return value.ToUpper(); - } - - string[] words = value.Split(new char[] { }, StringSplitOptions.RemoveEmptyEntries); - - var builder = new StringBuilder(); - foreach (string word in words) - { - builder.Append(word.Substring(0, 1).ToUpper()); - builder.Append(word.Substring(1)); - } - - return builder.ToString(); - } - - [HandlebarsWriter(WriterType.String)] - public string Prepend(string value, string pre) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return pre + value; - } - - [HandlebarsWriter(WriterType.String)] - public string Remove(string value, string oldValue) - { - return Replace(value, oldValue, string.Empty); - } - - [HandlebarsWriter(WriterType.String)] - public string Repeat(string value, int count) - { - return string.Concat(Enumerable.Repeat(value, count)); - } - - [HandlebarsWriter(WriterType.String)] - public string Replace(string value, string oldValue, string newValue) - { - if (value is null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (oldValue == null) - { - throw new ArgumentNullException(nameof(oldValue)); - } - - return value.Replace(oldValue, newValue); - } - - [HandlebarsWriter(WriterType.String)] - public string Reverse(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return new string(value.ToCharArray().Reverse().ToArray()); - } - - [HandlebarsWriter(WriterType.Value)] - public string[] Split(string value, string separator) - { - Guard.NotNull(value); - Guard.NotNull(separator); - - return separator.Length == 1 ? value.Split(separator[0]) : value.Split(separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - } - - [HandlebarsWriter(WriterType.String)] - public static string Titlecase(string value) - { - if (value is null) - { - throw new ArgumentNullException(nameof(value)); - } - - var tokens = value.Split(new[] { " ", "-" }, StringSplitOptions.RemoveEmptyEntries); - for (var i = 0; i < tokens.Length; i++) - { - var token = tokens[i]; - tokens[i] = token == token.ToUpper() - ? token - : token.Substring(0, 1).ToUpper() + token.Substring(1).ToLower(); - } - - return string.Join(" ", tokens); - } - - [HandlebarsWriter(WriterType.Value)] - public bool StartsWith(string value, string test) - { - if (value is null) - { - throw new ArgumentNullException(nameof(value)); - } - - return value.StartsWith(test); - } - - [HandlebarsWriter(WriterType.String)] - public string Trim(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return value.Trim(); - } - - [HandlebarsWriter(WriterType.String)] - public string TrimEnd(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return value.TrimEnd(); - } - - [HandlebarsWriter(WriterType.String)] - public string TrimStart(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return value.TrimStart(); - } - - [HandlebarsWriter(WriterType.String)] - public string Truncate(string value, int length) - { - Guard.Condition(length, l => l >= 0); - - if (string.IsNullOrEmpty(value) || value.Length <= length) - { - return value; - } - - return value.Substring(0, length); - } - - [HandlebarsWriter(WriterType.String)] - public string Uppercase(string value) - { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return value.ToUpper(); - } - - [HandlebarsWriter(WriterType.String)] - public string Format(object? value, string format) - { - var formatProvider = Context.Configuration.FormatProvider; - - // Attempt using a custom formatter from the format provider (if any) - var customFormatter = formatProvider?.GetFormat(typeof(ICustomFormatter)) as ICustomFormatter; - var formattedValue = customFormatter?.Format(format, value, formatProvider); - - // Fallback to IFormattable - formattedValue ??= (value as IFormattable)?.ToString(format, formatProvider); - - // Fallback to ToString - formattedValue ??= value?.ToString(); - - // Done - return formattedValue ?? string.Empty; - } - - [HandlebarsWriter(WriterType.Value)] - public WrappedString FormatAsString(object? value, string? format = null) - { - return new WrappedString(Format(value, format ?? string.Empty)); - } - - [HandlebarsWriter(WriterType.Value)] - public WrappedString ToWrappedString(object? value) - { - return FormatAsString(value); - } - - [HandlebarsWriter(WriterType.Value)] - public bool Equal(string value, string test) - { - return value == test; - } - - [HandlebarsWriter(WriterType.Value)] - public bool NotEqual(string value, string test) - { - return value != test; - } - - [HandlebarsWriter(WriterType.Value)] - public bool IsNullOrWhiteSpace(string value) - { - return string.IsNullOrWhiteSpace(value); - } - - [HandlebarsWriter(WriterType.Value)] - public bool IsNotNullOrWhiteSpace(string value) - { - return !string.IsNullOrWhiteSpace(value); - } - - [HandlebarsWriter(WriterType.Value)] - public bool IsNullOrEmpty(string value) - { - return string.IsNullOrEmpty(value); - } - - [HandlebarsWriter(WriterType.Value)] - public bool IsNotNullOrEmpty(string value) - { - return !string.IsNullOrEmpty(value); - } - - [HandlebarsWriter(WriterType.String)] - public string Substring(string value, int start, int? end = null) - { - Guard.NotNullOrEmpty(value); - return end is null ? value.Substring(start) : value.Substring(start, end.Value); - } - - public StringHelpers(IHandlebars context) : base(context) - { - } +using System; +using System.Collections; +using System.Linq; +using System.Text; +using HandlebarsDotNet.Helpers.Attributes; +using HandlebarsDotNet.Helpers.Enums; +using HandlebarsDotNet.Helpers.Models; +using HandlebarsDotNet.Helpers.Utils; +using Stef.Validation; + +namespace HandlebarsDotNet.Helpers.Helpers; + +/// +/// Some code copied from https://www.30secondsofcode.org/c-sharp/t/string/p/1 +/// and based on https://github.com/helpers/handlebars-helpers#string +/// +internal class StringHelpers : BaseHelpers, IHelpers +{ + public StringHelpers(IHandlebars context) : base(context) + { + } + + [HandlebarsWriter(WriterType.String)] + public string Append(string value, string append) + { + if (string.IsNullOrEmpty(value)) + { + return append; + } + + if (string.IsNullOrEmpty(append)) + { + return value; + } + + return value + append; + } + + [HandlebarsWriter(WriterType.String)] + public static string Base64Decode(string value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + var base64EncodedBytes = Convert.FromBase64String(value); + return Encoding.UTF8.GetString(base64EncodedBytes); + } + + [HandlebarsWriter(WriterType.String)] + public static string Base64Encode(string value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + var plainTextBytes = Encoding.UTF8.GetBytes(value); + return Convert.ToBase64String(plainTextBytes); + } + + [HandlebarsWriter(WriterType.String)] + public string Camelcase(string value) + { + if (string.IsNullOrEmpty(value) || value.Length < 2) + { + return value; + } + + string[] words = value.Split(new char[] { }, StringSplitOptions.RemoveEmptyEntries); + + var builder = new StringBuilder(words[0].ToLower()); + for (int i = 1; i < words.Length; i++) + { + builder.Append(words[i].Substring(0, 1).ToUpper()); + builder.Append(words[i].Substring(1)); + } + + return builder.ToString(); + } + + [HandlebarsWriter(WriterType.String)] + public string Capitalize(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + char[] chars = value.ToCharArray(); + chars[0] = char.ToUpper(chars[0]); + return new string(chars); + } + + [HandlebarsWriter(WriterType.Value)] + public object? Coalesce(params object?[] arguments) + { + foreach (var arg in arguments.Where(a => a is { } and not UndefinedBindingResult)) + { + if (arg is string stringValue) + { + if (!string.IsNullOrWhiteSpace(stringValue)) + { + return stringValue; + } + } + else + { + return arg; + } + } + + return null; + } + + [HandlebarsWriter(WriterType.String)] + public string Concat(string value, string append) + { + return Append(value, append); + } + + [HandlebarsWriter(WriterType.Value)] + public bool Contains(string value, string test) + { + Guard.NotNull(value); + + return value.Contains(test); + } + + [HandlebarsWriter(WriterType.String)] + public string Ellipsis(string value, int length) + { + Guard.Condition(length, l => l >= 0); + + if (string.IsNullOrEmpty(value) || value.Length <= length) + { + return value; + } + + return value.Substring(0, length) + "..."; + } + + [HandlebarsWriter(WriterType.Value)] + public bool Equal(string value, string test, object? stringComparisonType = null) + { + return EnumUtils.TryParse(stringComparisonType, out var comparisonType) ? string.Equals(value, test, comparisonType.Value) : value == test; + } + + [HandlebarsWriter(WriterType.Value)] + public bool Equals(string value, string test, object? stringComparisonType = null) + { + return Equal(value, test, stringComparisonType); + } + + [HandlebarsWriter(WriterType.String)] + public string Format(object? value, string format) + { + var formatProvider = Context.Configuration.FormatProvider; + + // Attempt using a custom formatter from the format provider (if any) + var customFormatter = formatProvider?.GetFormat(typeof(ICustomFormatter)) as ICustomFormatter; + var formattedValue = customFormatter?.Format(format, value, formatProvider); + + // Fallback to IFormattable + formattedValue ??= (value as IFormattable)?.ToString(format, formatProvider); + + // Fallback to ToString + formattedValue ??= value?.ToString(); + + // Done + return formattedValue ?? string.Empty; + } + + [HandlebarsWriter(WriterType.Value)] + public WrappedString FormatAsString(object? value, string? format = null) + { + return new WrappedString(Format(value, format ?? string.Empty)); + } + + [HandlebarsWriter(WriterType.Value)] + public bool IsNotNullOrEmpty(string value) + { + return !string.IsNullOrEmpty(value); + } + + [HandlebarsWriter(WriterType.Value)] + public bool IsNotNullOrWhiteSpace(string value) + { + return !string.IsNullOrWhiteSpace(value); + } + + [HandlebarsWriter(WriterType.Value)] + public bool IsNullOrEmpty(string value) + { + return string.IsNullOrEmpty(value); + } + + [HandlebarsWriter(WriterType.Value)] + public bool IsNullOrWhiteSpace(string value) + { + return string.IsNullOrWhiteSpace(value); + } + + [HandlebarsWriter(WriterType.Value)] + public bool IsString(object value) + { + return value is string; + } + + [HandlebarsWriter(WriterType.String)] + public string Join(IEnumerable values, string? separator = null) + { + if (values == null) + { + throw new ArgumentNullException(nameof(values)); + } + + return string.Join(separator ?? string.Empty, values.Cast()); + } + + [HandlebarsWriter(WriterType.String)] + public string Lowercase(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return value.ToLower(); + } + + [HandlebarsWriter(WriterType.Value)] + public bool NotEqual(string value, string test, object? stringComparisonType = null) + { + return !Equal(value, test, stringComparisonType); + } + + [HandlebarsWriter(WriterType.Value)] + public bool NotEquals(string value, string test, object? stringComparisonType = null) + { + return NotEqual(value, test, stringComparisonType); + } + + [HandlebarsWriter(WriterType.String)] + public string PadLeft(string value, int totalWidth, string padChar) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + return padChar?.Length > 0 ? value.PadLeft(totalWidth, padChar[0]) : value.PadLeft(totalWidth); + } + + [HandlebarsWriter(WriterType.String)] + public string PadRight(string value, int totalWidth, string padChar) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + return padChar?.Length > 0 ? value.PadRight(totalWidth, padChar[0]) : value.PadRight(totalWidth); + } + + [HandlebarsWriter(WriterType.String)] + public string Pascalcase(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + if (value.Length < 2) + { + return value.ToUpper(); + } + + string[] words = value.Split(new char[] { }, StringSplitOptions.RemoveEmptyEntries); + + var builder = new StringBuilder(); + foreach (string word in words) + { + builder.Append(word.Substring(0, 1).ToUpper()); + builder.Append(word.Substring(1)); + } + + return builder.ToString(); + } + + [HandlebarsWriter(WriterType.String)] + public string Prepend(string value, string pre) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return pre + value; + } + + [HandlebarsWriter(WriterType.String)] + public string Remove(string value, string oldValue) + { + return Replace(value, oldValue, string.Empty); + } + + [HandlebarsWriter(WriterType.String)] + public string Repeat(string value, int count) + { + return string.Concat(Enumerable.Repeat(value, count)); + } + + [HandlebarsWriter(WriterType.String)] + public string Replace(string value, string oldValue, string newValue) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (oldValue == null) + { + throw new ArgumentNullException(nameof(oldValue)); + } + + return value.Replace(oldValue, newValue); + } + + [HandlebarsWriter(WriterType.String)] + public string Reverse(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return new string(value.ToCharArray().Reverse().ToArray()); + } + + [HandlebarsWriter(WriterType.Value)] + public string[] Split(string value, string separator) + { + Guard.NotNull(value); + Guard.NotNull(separator); + + return separator.Length == 1 ? value.Split(separator[0]) : value.Split(separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + } + + [HandlebarsWriter(WriterType.Value)] + public bool StartsWith(string value, string test) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + return value.StartsWith(test); + } + + [HandlebarsWriter(WriterType.String)] + public string Substring(string value, int start, int? end = null) + { + Guard.NotNullOrEmpty(value); + return end is null ? value.Substring(start) : value.Substring(start, end.Value); + } + + [HandlebarsWriter(WriterType.String)] + public static string Titlecase(string value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + var tokens = value.Split(new[] { " ", "-" }, StringSplitOptions.RemoveEmptyEntries); + for (var i = 0; i < tokens.Length; i++) + { + var token = tokens[i]; + tokens[i] = token == token.ToUpper() + ? token + : token.Substring(0, 1).ToUpper() + token.Substring(1).ToLower(); + } + + return string.Join(" ", tokens); + } + + [HandlebarsWriter(WriterType.String)] + public string Trim(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return value.Trim(); + } + + [HandlebarsWriter(WriterType.String)] + public string TrimEnd(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return value.TrimEnd(); + } + + [HandlebarsWriter(WriterType.String)] + public string TrimStart(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return value.TrimStart(); + } + + [HandlebarsWriter(WriterType.String)] + public string Truncate(string value, int length) + { + Guard.Condition(length, l => l >= 0); + + if (string.IsNullOrEmpty(value) || value.Length <= length) + { + return value; + } + + return value.Substring(0, length); + } + + [HandlebarsWriter(WriterType.String)] + public string Uppercase(string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + return value.ToUpper(); + } + + [HandlebarsWriter(WriterType.Value)] + public WrappedString ToWrappedString(object? value) + { + return FormatAsString(value); + } } \ No newline at end of file diff --git a/test/Handlebars.Net.Helpers.Tests/Helpers/StringHelpersTests.cs b/test/Handlebars.Net.Helpers.Tests/Helpers/StringHelpersTests.cs index 37d146f..9378778 100644 --- a/test/Handlebars.Net.Helpers.Tests/Helpers/StringHelpersTests.cs +++ b/test/Handlebars.Net.Helpers.Tests/Helpers/StringHelpersTests.cs @@ -366,12 +366,29 @@ public void Format_Null() public void Equal(string value, string test, bool expected) { // Act - var result = _sut.Equal(value, test); + var equal = _sut.Equal(value, test); + var equals = _sut.Equals(value, test); // Assert - result.Should().Be(expected); + equal.Should().Be(expected); + equals.Should().Be(expected); } - + + [Theory] + [InlineData("Foo", "foo", "OrdinalIgnoreCase", true)] + [InlineData("Foo", "foo", "5", true)] + [InlineData("Foo", "foo", 5, true)] + public void EqualWithStringStringComparison(string value, string test, object stringComparison, bool expected) + { + // Act + var equal = _sut.Equal(value, test, stringComparison); + var equals = _sut.Equals(value, test, stringComparison); + + // Assert + equal.Should().Be(expected); + equals.Should().Be(expected); + } + [Theory] [InlineData("", "bar", true)] [InlineData("foo", "", true)] @@ -384,10 +401,27 @@ public void Equal(string value, string test, bool expected) public void NotEqual(string value, string test, bool expected) { // Act - var result = _sut.NotEqual(value, test); + var notEqual = _sut.NotEqual(value, test); + var notEquals = _sut.NotEquals(value, test); // Assert - result.Should().Be(expected); + notEqual.Should().Be(expected); + notEquals.Should().Be(expected); + } + + [Theory] + [InlineData("Foo", "foo", "OrdinalIgnoreCase", false)] + [InlineData("Foo", "foo", "5", false)] + [InlineData("Foo", "foo", 5, false)] + public void NotEqualWithStringStringComparison(string value, string test, object stringComparison, bool expected) + { + // Act + var notEqual = _sut.NotEqual(value, test, stringComparison); + var notEquals = _sut.NotEquals(value, test, stringComparison); + + // Assert + notEqual.Should().Be(expected); + notEquals.Should().Be(expected); } [Theory] diff --git a/test/Handlebars.Net.Helpers.Tests/Templates/StringHelpersTemplateTests.cs b/test/Handlebars.Net.Helpers.Tests/Templates/StringHelpersTemplateTests.cs index fa337d0..8db8772 100644 --- a/test/Handlebars.Net.Helpers.Tests/Templates/StringHelpersTemplateTests.cs +++ b/test/Handlebars.Net.Helpers.Tests/Templates/StringHelpersTemplateTests.cs @@ -85,6 +85,25 @@ public void Equal(string template, string expected) result.Should().Be(expected); } + [Theory] + [InlineData("{{[String.Equal] \"foo\" \"Foo\" \"OrdinalIgnoreCase\"}}", "True")] + [InlineData("{{[String.Equal] \"foo\" \"Foo\" \"5\"}}", "True")] + [InlineData("{{[String.Equal] \"foo\" \"Foo\" 5}}", "True")] + [InlineData("{{[String.Equals] \"foo\" \"Foo\" \"OrdinalIgnoreCase\"}}", "True")] + [InlineData("{{[String.Equals] \"foo\" \"Foo\" \"5\"}}", "True")] + [InlineData("{{[String.Equals] \"foo\" \"Foo\" 5}}", "True")] + public void EqualWithStringComparison(string template, string expected) + { + // Arrange + var action = _handlebarsContext.Compile(template); + + // Act + var result = action(""); + + // Assert + result.Should().Be(expected); + } + [Theory] [InlineData("{{#String.IsString \"Hello\"}}yes{{else}}no{{/String.IsString}}", "yes")] [InlineData("{{#String.IsString 1}}yes{{else}}no{{/String.IsString}}", "no")] @@ -151,6 +170,25 @@ public void NotEqual(string template, string expected) result.Should().Be(expected); } + [Theory] + [InlineData("{{[String.NotEqual] \"foo\" \"Foo\" \"OrdinalIgnoreCase\"}}", "False")] + [InlineData("{{[String.NotEqual] \"foo\" \"Foo\" \"5\"}}", "False")] + [InlineData("{{[String.NotEqual] \"foo\" \"Foo\" 5}}", "False")] + [InlineData("{{[String.NotEquals] \"foo\" \"Foo\" \"OrdinalIgnoreCase\"}}", "False")] + [InlineData("{{[String.NotEquals] \"foo\" \"Foo\" \"5\"}}", "False")] + [InlineData("{{[String.NotEquals] \"foo\" \"Foo\" 5}}", "False")] + public void NotEqualWithStringComparison(string template, string expected) + { + // Arrange + var action = _handlebarsContext.Compile(template); + + // Act + var result = action(""); + + // Assert + result.Should().Be(expected); + } + [Theory] [InlineData("{{[String.Split] \"a,b,c\" ','}}", "a,b,c")] [InlineData("{{[String.Split] \"a_;b_;c\" \"_;\"}}", "a,b,c")]