diff --git a/Volo.Abp.sln b/Volo.Abp.sln index a2731b0256..05bd668f59 100644 --- a/Volo.Abp.sln +++ b/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 diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs index ec4abe08e3..66b9383c89 100644 --- a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs +++ b/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 { diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs index a2e03dbad5..42224c30d7 100644 --- a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs +++ b/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 diff --git a/src/Volo.Abp/Abp/Modularity/ModuleLoader.cs b/src/Volo.Abp/Abp/Modularity/ModuleLoader.cs index dd8b0b8e5c..7d7e8453b3 100644 --- a/src/Volo.Abp/Abp/Modularity/ModuleLoader.cs +++ b/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 { diff --git a/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs b/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs index 842bc53cb2..e08100fa78 100644 --- a/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs +++ b/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 FindDefaultServiceTypes(Type type) + { + var serviceTypes = new List(); + + 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 FilterInjectableTypes(this IEnumerable types) diff --git a/src/Volo.DependencyInjection/project.json b/src/Volo.DependencyInjection/project.json index 3f091a2fb8..dedb8eba0c 100644 --- a/src/Volo.DependencyInjection/project.json +++ b/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": { diff --git a/src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/CollectionExtensions.cs similarity index 95% rename from src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs rename to src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/CollectionExtensions.cs index a2e64aad9a..7c8c2903e7 100644 --- a/src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs +++ b/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 { /// /// Extension methods for Collections. diff --git a/src/Volo.ExtensionMethods/Collections/Generic/DictionaryExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/DictionaryExtensions.cs similarity index 100% rename from src/Volo.ExtensionMethods/Collections/Generic/DictionaryExtensions.cs rename to src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/DictionaryExtensions.cs diff --git a/src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/EnumerableExtensions.cs similarity index 98% rename from src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs rename to src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/EnumerableExtensions.cs index bfbc9fa9d6..01f67130c9 100644 --- a/src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs +++ b/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 { /// /// Extension methods for . diff --git a/src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/ListExtensions.cs similarity index 98% rename from src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs rename to src/Volo.ExtensionMethods/ExtensionMethods/Collections/Generic/ListExtensions.cs index 847b92d092..47c0a49612 100644 --- a/src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs +++ b/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 { /// /// Extension methods for . diff --git a/src/Volo.ExtensionMethods/ExtensionMethods/ComparableExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/ComparableExtensions.cs new file mode 100644 index 0000000000..032ef879e2 --- /dev/null +++ b/src/Volo.ExtensionMethods/ExtensionMethods/ComparableExtensions.cs @@ -0,0 +1,21 @@ +using System; + +namespace Abp.Extensions +{ + /// + /// Extension methods for . + /// + public static class ComparableExtensions + { + /// + /// Checks a value is between a minimum and maximum value. + /// + /// The value to be checked + /// Minimum (inclusive) value + /// Maximum (inclusive) value + public static bool IsBetween(this T value, T minInclusiveValue, T maxInclusiveValue) where T : IComparable + { + return value.CompareTo(minInclusiveValue) >= 0 && value.CompareTo(maxInclusiveValue) <= 0; + } + } +} \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/ExtensionMethods/DayOfWeekExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/DayOfWeekExtensions.cs new file mode 100644 index 0000000000..9bf633bcdc --- /dev/null +++ b/src/Volo.ExtensionMethods/ExtensionMethods/DayOfWeekExtensions.cs @@ -0,0 +1,26 @@ +using System; + +namespace Volo.ExtensionMethods +{ + /// + /// Extension methods for . + /// + public static class DayOfWeekExtensions + { + /// + /// Check if given value is weekend. + /// + public static bool IsWeekend(this DayOfWeek dayOfWeek) + { + return dayOfWeek.IsIn(DayOfWeek.Saturday, DayOfWeek.Sunday); + } + + /// + /// Check if given value is weekday. + /// + public static bool IsWeekday(this DayOfWeek dayOfWeek) + { + return dayOfWeek.IsIn(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday); + } + } +} \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/ExtensionMethods/EventHandlerExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/EventHandlerExtensions.cs new file mode 100644 index 0000000000..d1a0614a47 --- /dev/null +++ b/src/Volo.ExtensionMethods/ExtensionMethods/EventHandlerExtensions.cs @@ -0,0 +1,44 @@ +using System; + +namespace Abp.Extensions +{ + /// + /// Extension methods for . + /// + public static class EventHandlerExtensions + { + /// + /// Raises given event safely with given arguments. + /// + /// The event handler + /// Source of the event + public static void InvokeSafely(this EventHandler eventHandler, object sender) + { + eventHandler.InvokeSafely(sender, EventArgs.Empty); + } + + /// + /// Raises given event safely with given arguments. + /// + /// The event handler + /// Source of the event + /// Event argument + public static void InvokeSafely(this EventHandler eventHandler, object sender, EventArgs e) + { + eventHandler?.Invoke(sender, e); + } + + /// + /// Raises given event safely with given arguments. + /// + /// Type of the + /// The event handler + /// Source of the event + /// Event argument + public static void InvokeSafely(this EventHandler eventHandler, object sender, TEventArgs e) + where TEventArgs : EventArgs + { + eventHandler?.Invoke(sender, e); + } + } +} \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/ExtensionMethods/ExceptionExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/ExceptionExtensions.cs new file mode 100644 index 0000000000..e7ba296b41 --- /dev/null +++ b/src/Volo.ExtensionMethods/ExtensionMethods/ExceptionExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Runtime.ExceptionServices; + +namespace Volo.ExtensionMethods +{ + /// + /// Extension methods for class. + /// + public static class ExceptionExtensions + { + /// + /// Uses method to re-throws exception + /// while preserving stack trace. + /// + /// Exception to be re-thrown + public static void ReThrow(this Exception exception) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + } +} \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/ExtensionMethods/ObjectExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/ObjectExtensions.cs new file mode 100644 index 0000000000..c146b156b9 --- /dev/null +++ b/src/Volo.ExtensionMethods/ExtensionMethods/ObjectExtensions.cs @@ -0,0 +1,47 @@ +using System; +using System.Globalization; +using System.Linq; + +namespace Abp.Extensions +{ + /// + /// Extension methods for all objects. + /// + public static class ObjectExtensions + { + /// + /// Used to simplify and beautify casting an object to a type. + /// + /// Type to be casted + /// Object to cast + /// Casted object + public static T As(this object obj) + where T : class + { + return (T)obj; + } + + /// + /// Converts given object to a value type using method. + /// + /// Object to be converted + /// Type of the target object + /// Converted object + public static T To(this object obj) + where T : struct + { + return (T)Convert.ChangeType(obj, typeof(T), CultureInfo.InvariantCulture); + } + + /// + /// Check if an item is in a list. + /// + /// Item to check + /// List of items + /// Type of the items + public static bool IsIn(this T item, params T[] list) + { + return list.Contains(item); + } + } +} diff --git a/src/Volo.ExtensionMethods/ExtensionMethods/StringExtensions.cs b/src/Volo.ExtensionMethods/ExtensionMethods/StringExtensions.cs new file mode 100644 index 0000000000..a8212062c5 --- /dev/null +++ b/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! + + /// + /// Extension methods for String class. + /// + public static class StringExtensions + { + /// + /// Adds a char to end of given string if it does not ends with the char. + /// + public static string EnsureEndsWith(this string str, char c) + { + return EnsureEndsWith(str, c, StringComparison.Ordinal); + } + + /// + /// Adds a char to end of given string if it does not ends with the char. + /// + 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; + } + + + /// + /// Adds a char to beginning of given string if it does not starts with the char. + /// + public static string EnsureStartsWith(this string str, char c) + { + return EnsureStartsWith(str, c, StringComparison.Ordinal); + } + + /// + /// Adds a char to beginning of given string if it does not starts with the char. + /// + 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; + } + + /// + /// Indicates whether this string is null or an System.String.Empty string. + /// + public static bool IsNullOrEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + + /// + /// indicates whether this string is null, empty, or consists only of white-space characters. + /// + public static bool IsNullOrWhiteSpace(this string str) + { + return string.IsNullOrWhiteSpace(str); + } + + /// + /// Gets a substring of a string from beginning of the string. + /// + /// Thrown if is null + /// Thrown if is bigger that string's length + 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); + } + + /// + /// Converts line endings in the string to . + /// + public static string NormalizeLineEndings(this string str) + { + return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine); + } + + /// + /// Gets index of nth occurence of a char in a string. + /// + /// source string to be searched + /// Char to search in + /// Count of the occurence + 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; + } + + /// + /// Removes first occurrence of the given postfixes from end of the given string. + /// + /// The string. + /// one or more postfix. + /// Modified string or the same string if it has not any of given postfixes + 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; + } + + /// + /// Removes first occurrence of the given prefixes from beginning of the given string. + /// + /// The string. + /// one or more prefix. + /// Modified string or the same string if it has not any of given prefixes + 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; + } + + /// + /// Gets a substring of a string from end of the string. + /// + /// Thrown if is null + /// Thrown if is bigger that string's length + 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); + } + + /// + /// Uses string.Split method to split given string by given separator. + /// + public static string[] Split(this string str, string separator) + { + return str.Split(new[] { separator }, StringSplitOptions.None); + } + + /// + /// Uses string.Split method to split given string by given separator. + /// + public static string[] Split(this string str, string separator, StringSplitOptions options) + { + return str.Split(new[] { separator }, options); + } + + /// + /// Uses string.Split method to split given string by . + /// + public static string[] SplitToLines(this string str) + { + return str.Split(Environment.NewLine); + } + + /// + /// Uses string.Split method to split given string by . + /// + public static string[] SplitToLines(this string str, StringSplitOptions options) + { + return str.Split(Environment.NewLine, options); + } + + /// + /// Converts PascalCase string to camelCase string. + /// + /// String to convert + /// camelCase of the string + 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); + } + + /// + /// Converts given PascalCase/camelCase string to sentence (by splitting words by space). + /// Example: "ThisIsSampleSentence" is converted to "This is a sample sentence". + /// + /// String to convert. + 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])); + } + + /// + /// Converts string to enum value. + /// + /// Type of enum + /// String value to convert + /// Returns enum object + public static T ToEnum(this string value) + where T : struct + { + Check.NotNull(value, nameof(value)); + return (T)Enum.Parse(typeof(T), value); + } + + /// + /// Converts string to enum value. + /// + /// Type of enum + /// String value to convert + /// Ignore case + /// Returns enum object + public static T ToEnum(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(); + } + } + + /// + /// Converts camelCase string to PascalCase string. + /// + /// String to convert + /// PascalCase of the string + 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); + } + + /// + /// Gets a substring of a string from beginning of the string if it exceeds maximum length. + /// + /// Thrown if is null + public static string Truncate(this string str, int maxLength) + { + if (str == null) + { + return null; + } + + if (str.Length <= maxLength) + { + return str; + } + + return str.Left(maxLength); + } + + /// + /// 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. + /// + /// Thrown if is null + public static string TruncateWithPostfix(this string str, int maxLength) + { + return TruncateWithPostfix(str, maxLength, "..."); + } + + /// + /// Gets a substring of a string from beginning of the string if it exceeds maximum length. + /// It adds given to end of the string if it's truncated. + /// Returning string can not be longer than maxLength. + /// + /// Thrown if is null + 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; + } + } +} \ No newline at end of file diff --git a/test/Apps/AspNetCoreDemo/Startup.cs b/test/Apps/AspNetCoreDemo/Startup.cs index a9724493d3..a790b82084 100644 --- a/test/Apps/AspNetCoreDemo/Startup.cs +++ b/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 { diff --git a/test/Volo.ExtensionMethods.Tests/ComparableExtensions_Tests.cs b/test/Volo.ExtensionMethods.Tests/ComparableExtensions_Tests.cs new file mode 100644 index 0000000000..eee8ac090d --- /dev/null +++ b/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); + } + } +} \ No newline at end of file diff --git a/test/Volo.ExtensionMethods.Tests/DayOfWeekExtensions_Tests.cs b/test/Volo.ExtensionMethods.Tests/DayOfWeekExtensions_Tests.cs new file mode 100644 index 0000000000..cf22fccc54 --- /dev/null +++ b/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); + } + } +} \ No newline at end of file diff --git a/test/Volo.ExtensionMethods.Tests/ObjectExtension_Test.cs b/test/Volo.ExtensionMethods.Tests/ObjectExtension_Test.cs new file mode 100644 index 0000000000..7d4c71316d --- /dev/null +++ b/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().ShouldNotBe(null); + + obj = null; + obj.As().ShouldBe(null); + } + + [Fact] + public void To_Tests() + { + "42".To().ShouldBeOfType().ShouldBe(42); + "42".To().ShouldBeOfType().ShouldBe(42); + + "28173829281734".To().ShouldBeOfType().ShouldBe(28173829281734); + "28173829281734".To().ShouldBeOfType().ShouldBe(28173829281734); + + "2.0".To().ShouldBe(2.0); + "0.2".To().ShouldBe(0.2); + (2.0).To().ShouldBe(2); + + "false".To().ShouldBeOfType().ShouldBe(false); + "True".To().ShouldBeOfType().ShouldBe(true); + + Assert.Throws(() => "test".To()); + Assert.Throws(() => "test".To()); + } + + [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); + } + } +} diff --git a/test/Volo.ExtensionMethods.Tests/Properties/AssemblyInfo.cs b/test/Volo.ExtensionMethods.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..e962b3f9cf --- /dev/null +++ b/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")] diff --git a/test/Volo.ExtensionMethods.Tests/StringExtensions_Tests.cs b/test/Volo.ExtensionMethods.Tests/StringExtensions_Tests.cs new file mode 100644 index 0000000000..f05166f86e --- /dev/null +++ b/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().ShouldBe(MyEnum.MyValue1); + "MyValue2".ToEnum().ShouldBe(MyEnum.MyValue2); + } + + private enum MyEnum + { + MyValue1, + MyValue2 + } + } +} \ No newline at end of file diff --git a/test/Volo.ExtensionMethods.Tests/Volo.ExtensionMethods.Tests.xproj b/test/Volo.ExtensionMethods.Tests/Volo.ExtensionMethods.Tests.xproj new file mode 100644 index 0000000000..7476ebf9d1 --- /dev/null +++ b/test/Volo.ExtensionMethods.Tests/Volo.ExtensionMethods.Tests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + b520b696-86c7-46d2-a359-c2e9013a7bed + Volo.ExtensionMethods.Tests + .\obj + .\bin\ + v4.6.1 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Volo.ExtensionMethods.Tests/project.json b/test/Volo.ExtensionMethods.Tests/project.json new file mode 100644 index 0000000000..8ac5f87aa2 --- /dev/null +++ b/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" + } + } + } + } +}