Browse Source

Added extension methods.

pull/81/head
Halil İbrahim Kalkan 9 years ago
parent
commit
59c7b01128
  1. 7
      Volo.Abp.sln
  2. 6
      src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs
  3. 4
      src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs
  4. 2
      src/Volo.Abp/Abp/Modularity/ModuleLoader.cs
  5. 45
      src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs
  6. 5
      src/Volo.DependencyInjection/project.json
  7. 3
      src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/CollectionExtensions.cs
  8. 0
      src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/DictionaryExtensions.cs
  9. 2
      src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/EnumerableExtensions.cs
  10. 2
      src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/ListExtensions.cs
  11. 21
      src/Volo.ExtensionMethods/ExtensionMethods/ComparableExtensions.cs
  12. 26
      src/Volo.ExtensionMethods/ExtensionMethods/DayOfWeekExtensions.cs
  13. 44
      src/Volo.ExtensionMethods/ExtensionMethods/EventHandlerExtensions.cs
  14. 21
      src/Volo.ExtensionMethods/ExtensionMethods/ExceptionExtensions.cs
  15. 47
      src/Volo.ExtensionMethods/ExtensionMethods/ObjectExtensions.cs
  16. 400
      src/Volo.ExtensionMethods/ExtensionMethods/StringExtensions.cs
  17. 1
      test/Apps/AspNetCoreDemo/Startup.cs
  18. 26
      test/Volo.ExtensionMethods.Tests/ComparableExtensions_Tests.cs
  19. 29
      test/Volo.ExtensionMethods.Tests/DayOfWeekExtensions_Tests.cs
  20. 56
      test/Volo.ExtensionMethods.Tests/ObjectExtension_Test.cs
  21. 19
      test/Volo.ExtensionMethods.Tests/Properties/AssemblyInfo.cs
  22. 178
      test/Volo.ExtensionMethods.Tests/StringExtensions_Tests.cs
  23. 22
      test/Volo.ExtensionMethods.Tests/Volo.ExtensionMethods.Tests.xproj
  24. 21
      test/Volo.ExtensionMethods.Tests/project.json

7
Volo.Abp.sln

@ -42,6 +42,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.ExtensionMethods", "sr
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.CodeAnnotations", "src\Volo.CodeAnnotations\Volo.CodeAnnotations.xproj", "{161A6C10-00FF-4348-993F-D19893ABC57C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.ExtensionMethods.Tests", "test\Volo.ExtensionMethods.Tests\Volo.ExtensionMethods.Tests.xproj", "{B520B696-86C7-46D2-A359-C2E9013A7BED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -88,6 +90,10 @@ Global
{161A6C10-00FF-4348-993F-D19893ABC57C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{161A6C10-00FF-4348-993F-D19893ABC57C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{161A6C10-00FF-4348-993F-D19893ABC57C}.Release|Any CPU.Build.0 = Release|Any CPU
{B520B696-86C7-46D2-A359-C2E9013A7BED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B520B696-86C7-46D2-A359-C2E9013A7BED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B520B696-86C7-46D2-A359-C2E9013A7BED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B520B696-86C7-46D2-A359-C2E9013A7BED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -108,5 +114,6 @@ Global
{12E14D95-4ABA-4290-AB1D-CCF5EB158411} = {A3A3B258-B3D5-4FDE-9D84-CAA8CBB70586}
{FC889503-0BF4-4959-AC80-F51073787025} = {9A4A646B-CC96-44FB-A717-E50C5C148B54}
{161A6C10-00FF-4348-993F-D19893ABC57C} = {9A4A646B-CC96-44FB-A717-E50C5C148B54}
{B520B696-86C7-46D2-A359-C2E9013A7BED} = {82B41A0A-6068-410F-9C6B-2508CA763E21}
EndGlobalSection
EndGlobal

6
src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs

@ -1,8 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Volo.DependencyInjection;
namespace Microsoft.AspNetCore.Builder
namespace Volo.Abp.AspNetCore
{
public static class AbpApplicationBuilderExtensions
{

4
src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs

@ -1,7 +1,7 @@
using Volo.Abp;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace Microsoft.Extensions.DependencyInjection
namespace Volo.Abp.AspNetCore
{
//TODO: Decide to move ABP?
public static class AbpServiceCollectionExtensions

2
src/Volo.Abp/Abp/Modularity/ModuleLoader.cs

@ -4,7 +4,7 @@ using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Volo.Collections.Generic;
using Volo.ExtensionMethods.Collections.Generic;
namespace Volo.Abp.Modularity
{

45
src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Abp.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Volo.Internal;
@ -31,22 +32,48 @@ namespace Volo.DependencyInjection
public static void AddType(this IServiceCollection services, Type type)
{
//TODO: Find exposed services for the type
//TODO: Make this code extensible, so we can add other conventions!
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
foreach (var serviceType in FindDefaultServiceTypes(type))
{
services.AddTransient(type);
}
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
{
services.AddTransient(serviceType, type);
}
if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
{
services.AddSingleton(type);
if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
{
services.AddSingleton(serviceType, type);
}
if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
{
services.AddScoped(serviceType, type);
}
}
}
if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
private static List<Type> FindDefaultServiceTypes(Type type)
{
var serviceTypes = new List<Type>();
serviceTypes.Add(type);
foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
{
services.AddScoped(type);
var interfaceName = interfaceType.Name;
if (interfaceName.StartsWith("I"))
{
interfaceName = interfaceName.Right(interfaceName.Length - 1);
}
if (type.Name.EndsWith(interfaceName))
{
serviceTypes.Add(interfaceType);
}
}
return serviceTypes;
}
private static IEnumerable<Type> FilterInjectableTypes(this IEnumerable<Type> types)

5
src/Volo.DependencyInjection/project.json

@ -1,9 +1,10 @@
{
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.1",
"Microsoft.Extensions.DependencyInjection": "1.1.0"
"Microsoft.Extensions.DependencyInjection": "1.1.0",
"Volo.ExtensionMethods": "1.0.0-*"
},
"frameworks": {

3
src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs → src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/CollectionExtensions.cs

@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.CodeAnnotations;
namespace Volo.Collections.Generic
namespace Volo.ExtensionMethods.Collections.Generic
{
/// <summary>
/// Extension methods for Collections.

0
src/Volo.ExtensionMethods/Collections/Generic/DictionaryExtensions.cs → src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/DictionaryExtensions.cs

2
src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs → src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/EnumerableExtensions.cs

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
namespace Volo.Collections.Generic
namespace Volo.ExtensionMethods.Collections.Generic
{
/// <summary>
/// Extension methods for <see cref="IEnumerable{T}"/>.

2
src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs → src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/ListExtensions.cs

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace Volo.Collections.Generic
namespace Volo.ExtensionMethods.Collections.Generic
{
/// <summary>
/// Extension methods for <see cref="IList{T}"/>.

21
src/Volo.ExtensionMethods/ExtensionMethods/ComparableExtensions.cs

@ -0,0 +1,21 @@
using System;
namespace Abp.Extensions
{
/// <summary>
/// Extension methods for <see cref="IComparable{T}"/>.
/// </summary>
public static class ComparableExtensions
{
/// <summary>
/// Checks a value is between a minimum and maximum value.
/// </summary>
/// <param name="value">The value to be checked</param>
/// <param name="minInclusiveValue">Minimum (inclusive) value</param>
/// <param name="maxInclusiveValue">Maximum (inclusive) value</param>
public static bool IsBetween<T>(this T value, T minInclusiveValue, T maxInclusiveValue) where T : IComparable<T>
{
return value.CompareTo(minInclusiveValue) >= 0 && value.CompareTo(maxInclusiveValue) <= 0;
}
}
}

26
src/Volo.ExtensionMethods/ExtensionMethods/DayOfWeekExtensions.cs

@ -0,0 +1,26 @@
using System;
namespace Volo.ExtensionMethods
{
/// <summary>
/// Extension methods for <see cref="DayOfWeekExtensions"/>.
/// </summary>
public static class DayOfWeekExtensions
{
/// <summary>
/// Check if given <see cref="DayOfWeek"/> value is weekend.
/// </summary>
public static bool IsWeekend(this DayOfWeek dayOfWeek)
{
return dayOfWeek.IsIn(DayOfWeek.Saturday, DayOfWeek.Sunday);
}
/// <summary>
/// Check if given <see cref="DayOfWeek"/> value is weekday.
/// </summary>
public static bool IsWeekday(this DayOfWeek dayOfWeek)
{
return dayOfWeek.IsIn(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday);
}
}
}

44
src/Volo.ExtensionMethods/ExtensionMethods/EventHandlerExtensions.cs

@ -0,0 +1,44 @@
using System;
namespace Abp.Extensions
{
/// <summary>
/// Extension methods for <see cref="EventHandler"/>.
/// </summary>
public static class EventHandlerExtensions
{
/// <summary>
/// Raises given event safely with given arguments.
/// </summary>
/// <param name="eventHandler">The event handler</param>
/// <param name="sender">Source of the event</param>
public static void InvokeSafely(this EventHandler eventHandler, object sender)
{
eventHandler.InvokeSafely(sender, EventArgs.Empty);
}
/// <summary>
/// Raises given event safely with given arguments.
/// </summary>
/// <param name="eventHandler">The event handler</param>
/// <param name="sender">Source of the event</param>
/// <param name="e">Event argument</param>
public static void InvokeSafely(this EventHandler eventHandler, object sender, EventArgs e)
{
eventHandler?.Invoke(sender, e);
}
/// <summary>
/// Raises given event safely with given arguments.
/// </summary>
/// <typeparam name="TEventArgs">Type of the <see cref="EventArgs"/></typeparam>
/// <param name="eventHandler">The event handler</param>
/// <param name="sender">Source of the event</param>
/// <param name="e">Event argument</param>
public static void InvokeSafely<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e)
where TEventArgs : EventArgs
{
eventHandler?.Invoke(sender, e);
}
}
}

21
src/Volo.ExtensionMethods/ExtensionMethods/ExceptionExtensions.cs

@ -0,0 +1,21 @@
using System;
using System.Runtime.ExceptionServices;
namespace Volo.ExtensionMethods
{
/// <summary>
/// Extension methods for <see cref="Exception"/> class.
/// </summary>
public static class ExceptionExtensions
{
/// <summary>
/// Uses <see cref="ExceptionDispatchInfo.Capture"/> method to re-throws exception
/// while preserving stack trace.
/// </summary>
/// <param name="exception">Exception to be re-thrown</param>
public static void ReThrow(this Exception exception)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
}

47
src/Volo.ExtensionMethods/ExtensionMethods/ObjectExtensions.cs

@ -0,0 +1,47 @@
using System;
using System.Globalization;
using System.Linq;
namespace Abp.Extensions
{
/// <summary>
/// Extension methods for all objects.
/// </summary>
public static class ObjectExtensions
{
/// <summary>
/// Used to simplify and beautify casting an object to a type.
/// </summary>
/// <typeparam name="T">Type to be casted</typeparam>
/// <param name="obj">Object to cast</param>
/// <returns>Casted object</returns>
public static T As<T>(this object obj)
where T : class
{
return (T)obj;
}
/// <summary>
/// Converts given object to a value type using <see cref="Convert.ChangeType(object,System.Type)"/> method.
/// </summary>
/// <param name="obj">Object to be converted</param>
/// <typeparam name="T">Type of the target object</typeparam>
/// <returns>Converted object</returns>
public static T To<T>(this object obj)
where T : struct
{
return (T)Convert.ChangeType(obj, typeof(T), CultureInfo.InvariantCulture);
}
/// <summary>
/// Check if an item is in a list.
/// </summary>
/// <param name="item">Item to check</param>
/// <param name="list">List of items</param>
/// <typeparam name="T">Type of the items</typeparam>
public static bool IsIn<T>(this T item, params T[] list)
{
return list.Contains(item);
}
}
}

400
src/Volo.ExtensionMethods/ExtensionMethods/StringExtensions.cs

@ -0,0 +1,400 @@
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Volo.CodeAnnotations;
using Volo.Collections.Generic;
namespace Abp.Extensions
{
//TODO: Not working properly with cultures!
/// <summary>
/// Extension methods for String class.
/// </summary>
public static class StringExtensions
{
/// <summary>
/// Adds a char to end of given string if it does not ends with the char.
/// </summary>
public static string EnsureEndsWith(this string str, char c)
{
return EnsureEndsWith(str, c, StringComparison.Ordinal);
}
/// <summary>
/// Adds a char to end of given string if it does not ends with the char.
/// </summary>
public static string EnsureEndsWith(this string str, char c, StringComparison comparisonType)
{
Check.NotNull(str, nameof(str));
if (str.EndsWith(c.ToString(), comparisonType))
{
return str;
}
return str + c;
}
/// <summary>
/// Adds a char to beginning of given string if it does not starts with the char.
/// </summary>
public static string EnsureStartsWith(this string str, char c)
{
return EnsureStartsWith(str, c, StringComparison.Ordinal);
}
/// <summary>
/// Adds a char to beginning of given string if it does not starts with the char.
/// </summary>
public static string EnsureStartsWith(this string str, char c, StringComparison comparisonType)
{
Check.NotNull(str, nameof(str));
if (str.StartsWith(c.ToString(), comparisonType))
{
return str;
}
return c + str;
}
/// <summary>
/// Indicates whether this string is null or an System.String.Empty string.
/// </summary>
public static bool IsNullOrEmpty(this string str)
{
return string.IsNullOrEmpty(str);
}
/// <summary>
/// indicates whether this string is null, empty, or consists only of white-space characters.
/// </summary>
public static bool IsNullOrWhiteSpace(this string str)
{
return string.IsNullOrWhiteSpace(str);
}
/// <summary>
/// Gets a substring of a string from beginning of the string.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
/// <exception cref="ArgumentException">Thrown if <paramref name="len"/> is bigger that string's length</exception>
public static string Left(this string str, int len)
{
Check.NotNull(str, nameof(str));
if (str.Length < len)
{
throw new ArgumentException("len argument can not be bigger than given string's length!");
}
return str.Substring(0, len);
}
/// <summary>
/// Converts line endings in the string to <see cref="Environment.NewLine"/>.
/// </summary>
public static string NormalizeLineEndings(this string str)
{
return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine);
}
/// <summary>
/// Gets index of nth occurence of a char in a string.
/// </summary>
/// <param name="str">source string to be searched</param>
/// <param name="c">Char to search in <see cref="str"/></param>
/// <param name="n">Count of the occurence</param>
public static int NthIndexOf(this string str, char c, int n)
{
Check.NotNull(str, nameof(str));
var count = 0;
for (var i = 0; i < str.Length; i++)
{
if (str[i] != c)
{
continue;
}
if ((++count) == n)
{
return i;
}
}
return -1;
}
/// <summary>
/// Removes first occurrence of the given postfixes from end of the given string.
/// </summary>
/// <param name="str">The string.</param>
/// <param name="postFixes">one or more postfix.</param>
/// <returns>Modified string or the same string if it has not any of given postfixes</returns>
public static string RemovePostFix(this string str, params string[] postFixes)
{
if (str.IsNullOrEmpty())
{
return null;
}
if (postFixes.IsNullOrEmpty())
{
return str;
}
foreach (var postFix in postFixes)
{
if (str.EndsWith(postFix))
{
return str.Left(str.Length - postFix.Length);
}
}
return str;
}
/// <summary>
/// Removes first occurrence of the given prefixes from beginning of the given string.
/// </summary>
/// <param name="str">The string.</param>
/// <param name="preFixes">one or more prefix.</param>
/// <returns>Modified string or the same string if it has not any of given prefixes</returns>
public static string RemovePreFix(this string str, params string[] preFixes)
{
if (str.IsNullOrEmpty())
{
return null;
}
if (preFixes.IsNullOrEmpty())
{
return str;
}
foreach (var preFix in preFixes)
{
if (str.StartsWith(preFix))
{
return str.Right(str.Length - preFix.Length);
}
}
return str;
}
/// <summary>
/// Gets a substring of a string from end of the string.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
/// <exception cref="ArgumentException">Thrown if <paramref name="len"/> is bigger that string's length</exception>
public static string Right(this string str, int len)
{
Check.NotNull(str, nameof(str));
if (str.Length < len)
{
throw new ArgumentException("len argument can not be bigger than given string's length!");
}
return str.Substring(str.Length - len, len);
}
/// <summary>
/// Uses string.Split method to split given string by given separator.
/// </summary>
public static string[] Split(this string str, string separator)
{
return str.Split(new[] { separator }, StringSplitOptions.None);
}
/// <summary>
/// Uses string.Split method to split given string by given separator.
/// </summary>
public static string[] Split(this string str, string separator, StringSplitOptions options)
{
return str.Split(new[] { separator }, options);
}
/// <summary>
/// Uses string.Split method to split given string by <see cref="Environment.NewLine"/>.
/// </summary>
public static string[] SplitToLines(this string str)
{
return str.Split(Environment.NewLine);
}
/// <summary>
/// Uses string.Split method to split given string by <see cref="Environment.NewLine"/>.
/// </summary>
public static string[] SplitToLines(this string str, StringSplitOptions options)
{
return str.Split(Environment.NewLine, options);
}
/// <summary>
/// Converts PascalCase string to camelCase string.
/// </summary>
/// <param name="str">String to convert</param>
/// <returns>camelCase of the string</returns>
public static string ToCamelCase(this string str)
{
if (string.IsNullOrWhiteSpace(str))
{
return str;
}
if (str.Length == 1)
{
return str.ToLower();
}
return char.ToLower(str[0]) + str.Substring(1);
}
/// <summary>
/// Converts given PascalCase/camelCase string to sentence (by splitting words by space).
/// Example: "ThisIsSampleSentence" is converted to "This is a sample sentence".
/// </summary>
/// <param name="str">String to convert.</param>
public static string ToSentenceCase(this string str)
{
if (string.IsNullOrWhiteSpace(str))
{
return str;
}
return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}
/// <summary>
/// Converts string to enum value.
/// </summary>
/// <typeparam name="T">Type of enum</typeparam>
/// <param name="value">String value to convert</param>
/// <returns>Returns enum object</returns>
public static T ToEnum<T>(this string value)
where T : struct
{
Check.NotNull(value, nameof(value));
return (T)Enum.Parse(typeof(T), value);
}
/// <summary>
/// Converts string to enum value.
/// </summary>
/// <typeparam name="T">Type of enum</typeparam>
/// <param name="value">String value to convert</param>
/// <param name="ignoreCase">Ignore case</param>
/// <returns>Returns enum object</returns>
public static T ToEnum<T>(this string value, bool ignoreCase)
where T : struct
{
Check.NotNull(value, nameof(value));
return (T)Enum.Parse(typeof(T), value, ignoreCase);
}
public static string ToMd5(this string str)
{
using (var md5 = MD5.Create())
{
var inputBytes = Encoding.UTF8.GetBytes(str);
var hashBytes = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var hashByte in hashBytes)
{
sb.Append(hashByte.ToString("X2"));
}
return sb.ToString();
}
}
/// <summary>
/// Converts camelCase string to PascalCase string.
/// </summary>
/// <param name="str">String to convert</param>
/// <returns>PascalCase of the string</returns>
public static string ToPascalCase(this string str)
{
if (string.IsNullOrWhiteSpace(str))
{
return str;
}
if (str.Length == 1)
{
return str.ToUpper();
}
return char.ToUpper(str[0]) + str.Substring(1);
}
/// <summary>
/// Gets a substring of a string from beginning of the string if it exceeds maximum length.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
public static string Truncate(this string str, int maxLength)
{
if (str == null)
{
return null;
}
if (str.Length <= maxLength)
{
return str;
}
return str.Left(maxLength);
}
/// <summary>
/// Gets a substring of a string from beginning of the string if it exceeds maximum length.
/// It adds a "..." postfix to end of the string if it's truncated.
/// Returning string can not be longer than maxLength.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
public static string TruncateWithPostfix(this string str, int maxLength)
{
return TruncateWithPostfix(str, maxLength, "...");
}
/// <summary>
/// Gets a substring of a string from beginning of the string if it exceeds maximum length.
/// It adds given <paramref name="postfix"/> to end of the string if it's truncated.
/// Returning string can not be longer than maxLength.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
public static string TruncateWithPostfix(this string str, int maxLength, string postfix)
{
if (str == null)
{
return null;
}
if (str == string.Empty || maxLength == 0)
{
return string.Empty;
}
if (str.Length <= maxLength)
{
return str;
}
if (maxLength <= postfix.Length)
{
return postfix.Left(maxLength);
}
return str.Left(maxLength - postfix.Length) + postfix;
}
}
}

1
test/Apps/AspNetCoreDemo/Startup.cs

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.AspNetCore;
namespace AspNetCoreDemo
{

26
test/Volo.ExtensionMethods.Tests/ComparableExtensions_Tests.cs

@ -0,0 +1,26 @@
using System;
using Abp.Extensions;
using Shouldly;
using Xunit;
namespace Abp.Tests.Extensions
{
public class ComparableExtensions_Tests
{
[Fact]
public void IsBetween_Test()
{
//Number
var number = 5;
number.IsBetween(1, 10).ShouldBe(true);
number.IsBetween(1, 5).ShouldBe(true);
number.IsBetween(5, 10).ShouldBe(true);
number.IsBetween(10, 20).ShouldBe(false);
//DateTime
var dateTimeValue = new DateTime(2014, 10, 4, 18, 20, 42, 0);
dateTimeValue.IsBetween(new DateTime(2014, 1, 1), new DateTime(2015, 1, 1)).ShouldBe(true);
dateTimeValue.IsBetween(new DateTime(2015, 1, 1), new DateTime(2016, 1, 1)).ShouldBe(false);
}
}
}

29
test/Volo.ExtensionMethods.Tests/DayOfWeekExtensions_Tests.cs

@ -0,0 +1,29 @@
using System;
using Abp.Extensions;
using Shouldly;
using Xunit;
namespace Abp.Tests.Extensions
{
public class DayOfWeekExtensions_Tests
{
[Fact]
public void Weekend_Weekday_Test()
{
DayOfWeek.Monday.IsWeekday().ShouldBe(true);
DayOfWeek.Monday.IsWeekend().ShouldBe(false);
DayOfWeek.Saturday.IsWeekend().ShouldBe(true);
DayOfWeek.Saturday.IsWeekday().ShouldBe(false);
var datetime1 = new DateTime(2014, 10, 5, 16, 37, 25); //Sunday
var datetime2 = new DateTime(2014, 10, 7, 16, 37, 25); //Tuesday
datetime1.DayOfWeek.IsWeekend().ShouldBe(true);
datetime2.DayOfWeek.IsWeekend().ShouldBe(false);
datetime1.DayOfWeek.IsWeekday().ShouldBe(false);
datetime2.DayOfWeek.IsWeekday().ShouldBe(true);
}
}
}

56
test/Volo.ExtensionMethods.Tests/ObjectExtension_Test.cs

@ -0,0 +1,56 @@
using System;
using Abp.Extensions;
using Shouldly;
using Xunit;
namespace Abp.Tests.Extensions
{
public class ObjectExtensions_Tests
{
[Fact]
public void As_Test()
{
var obj = (object)new ObjectExtensions_Tests();
obj.As<ObjectExtensions_Tests>().ShouldNotBe(null);
obj = null;
obj.As<ObjectExtensions_Tests>().ShouldBe(null);
}
[Fact]
public void To_Tests()
{
"42".To<int>().ShouldBeOfType<int>().ShouldBe(42);
"42".To<Int32>().ShouldBeOfType<Int32>().ShouldBe(42);
"28173829281734".To<long>().ShouldBeOfType<long>().ShouldBe(28173829281734);
"28173829281734".To<Int64>().ShouldBeOfType<Int64>().ShouldBe(28173829281734);
"2.0".To<double>().ShouldBe(2.0);
"0.2".To<double>().ShouldBe(0.2);
(2.0).To<int>().ShouldBe(2);
"false".To<bool>().ShouldBeOfType<bool>().ShouldBe(false);
"True".To<bool>().ShouldBeOfType<bool>().ShouldBe(true);
Assert.Throws<FormatException>(() => "test".To<bool>());
Assert.Throws<FormatException>(() => "test".To<int>());
}
[Fact]
public void IsIn_Test()
{
5.IsIn(1, 3, 5, 7).ShouldBe(true);
6.IsIn(1, 3, 5, 7).ShouldBe(false);
int? number = null;
number.IsIn(2, 3, 5).ShouldBe(false);
var str = "a";
str.IsIn("a", "b", "c").ShouldBe(true);
str = null;
str.IsIn("a", "b", "c").ShouldBe(false);
}
}
}

19
test/Volo.ExtensionMethods.Tests/Properties/AssemblyInfo.cs

@ -0,0 +1,19 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Volo.ExtensionMethods.Tests")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b520b696-86c7-46d2-a359-c2e9013a7bed")]

178
test/Volo.ExtensionMethods.Tests/StringExtensions_Tests.cs

@ -0,0 +1,178 @@
using System.Globalization;
using Abp.Extensions;
using Shouldly;
using Xunit;
namespace Abp.Tests.Extensions
{
public class StringExtensions_Tests
{
public StringExtensions_Tests()
{
//TODO: Temporary workaround! See StringExtensions
CultureInfo.CurrentUICulture = new CultureInfo("en-US");
CultureInfo.CurrentCulture = new CultureInfo("en-US");
}
[Fact]
public void EnsureEndsWith_Test()
{
//Expected use-cases
"Test".EnsureEndsWith('!').ShouldBe("Test!");
"Test!".EnsureEndsWith('!').ShouldBe("Test!");
@"C:\test\folderName".EnsureEndsWith('\\').ShouldBe(@"C:\test\folderName\");
@"C:\test\folderName\".EnsureEndsWith('\\').ShouldBe(@"C:\test\folderName\");
//Case differences
"TurkeY".EnsureEndsWith('y').ShouldBe("TurkeYy");
}
[Fact]
public void EnsureStartsWith_Test()
{
//Expected use-cases
"Test".EnsureStartsWith('~').ShouldBe("~Test");
"~Test".EnsureStartsWith('~').ShouldBe("~Test");
//Case differences
"Turkey".EnsureStartsWith('t').ShouldBe("tTurkey");
}
[Fact]
public void ToPascalCase_Test()
{
(null as string).ToPascalCase().ShouldBe(null);
"helloWorld".ToPascalCase().ShouldBe("HelloWorld");
"istanbul".ToPascalCase().ShouldBe("Istanbul");
}
[Fact]
public void ToCamelCase_Test()
{
(null as string).ToCamelCase().ShouldBe(null);
"HelloWorld".ToCamelCase().ShouldBe("helloWorld");
"Istanbul".ToCamelCase().ShouldBe("istanbul");
}
[Fact]
public void ToSentenceCase_Test()
{
(null as string).ToSentenceCase().ShouldBe(null);
"HelloWorld".ToSentenceCase().ShouldBe("Hello world");
"HelloIsparta".ToSentenceCase().ShouldBe("Hello isparta");
}
[Fact]
public void Right_Test()
{
const string str = "This is a test string";
str.Right(3).ShouldBe("ing");
str.Right(0).ShouldBe("");
str.Right(str.Length).ShouldBe(str);
}
[Fact]
public void Left_Test()
{
const string str = "This is a test string";
str.Left(3).ShouldBe("Thi");
str.Left(0).ShouldBe("");
str.Left(str.Length).ShouldBe(str);
}
[Fact]
public void NormalizeLineEndings_Test()
{
const string str = "This\r\n is a\r test \n string";
var normalized = str.NormalizeLineEndings();
var lines = normalized.SplitToLines();
lines.Length.ShouldBe(4);
}
[Fact]
public void NthIndexOf_Test()
{
const string str = "This is a test string";
str.NthIndexOf('i', 0).ShouldBe(-1);
str.NthIndexOf('i', 1).ShouldBe(2);
str.NthIndexOf('i', 2).ShouldBe(5);
str.NthIndexOf('i', 3).ShouldBe(18);
str.NthIndexOf('i', 4).ShouldBe(-1);
}
[Fact]
public void Truncate_Test()
{
const string str = "This is a test string";
const string nullValue = null;
str.Truncate(7).ShouldBe("This is");
str.Truncate(0).ShouldBe("");
str.Truncate(100).ShouldBe(str);
nullValue.Truncate(5).ShouldBe(null);
}
[Fact]
public void TruncateWithPostFix_Test()
{
const string str = "This is a test string";
const string nullValue = null;
str.TruncateWithPostfix(3).ShouldBe("...");
str.TruncateWithPostfix(12).ShouldBe("This is a...");
str.TruncateWithPostfix(0).ShouldBe("");
str.TruncateWithPostfix(100).ShouldBe(str);
nullValue.Truncate(5).ShouldBe(null);
str.TruncateWithPostfix(3, "~").ShouldBe("Th~");
str.TruncateWithPostfix(12, "~").ShouldBe("This is a t~");
str.TruncateWithPostfix(0, "~").ShouldBe("");
str.TruncateWithPostfix(100, "~").ShouldBe(str);
nullValue.TruncateWithPostfix(5, "~").ShouldBe(null);
}
[Fact]
public void RemovePostFix_Tests()
{
//null case
(null as string).RemovePreFix("Test").ShouldBeNull();
//Simple case
"MyTestAppService".RemovePostFix("AppService").ShouldBe("MyTest");
"MyTestAppService".RemovePostFix("Service").ShouldBe("MyTestApp");
//Multiple postfix (orders of postfixes are important)
"MyTestAppService".RemovePostFix("AppService", "Service").ShouldBe("MyTest");
"MyTestAppService".RemovePostFix("Service", "AppService").ShouldBe("MyTestApp");
//Unmatched case
"MyTestAppService".RemovePostFix("Unmatched").ShouldBe("MyTestAppService");
}
[Fact]
public void RemovePreFix_Tests()
{
"Home.Index".RemovePreFix("NotMatchedPostfix").ShouldBe("Home.Index");
"Home.About".RemovePreFix("Home.").ShouldBe("About");
}
[Fact]
public void ToEnum_Test()
{
"MyValue1".ToEnum<MyEnum>().ShouldBe(MyEnum.MyValue1);
"MyValue2".ToEnum<MyEnum>().ShouldBe(MyEnum.MyValue2);
}
private enum MyEnum
{
MyValue1,
MyValue2
}
}
}

22
test/Volo.ExtensionMethods.Tests/Volo.ExtensionMethods.Tests.xproj

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>b520b696-86c7-46d2-a359-c2e9013a7bed</ProjectGuid>
<RootNamespace>Volo.ExtensionMethods.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

21
test/Volo.ExtensionMethods.Tests/project.json

@ -0,0 +1,21 @@
{
"version": "1.0.0-*",
"testRunner": "xunit",
"dependencies": {
"AbpTestBase": "1.0.0-*",
"Volo.ExtensionMethods": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
}
}
Loading…
Cancel
Save