From 37e5752d61aa9e22049f31d1945ab89b0d0ac34c Mon Sep 17 00:00:00 2001 From: wangjun Date: Wed, 28 Jun 2023 15:07:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0Lion.AbpPro.Core?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Lion.AbpPro.Core/GlobalUsings.cs | 1 + .../Generic/CollectionExtensions.cs | 4 +- .../System/DateTimeExtensions.cs | 78 +---- .../Lion.AbpPro.Core/System/EnumExtensions.cs | 1 - .../System/ExceptionExtensions.cs | 43 +-- .../Lion.AbpPro.Core/System/LongExtensions.cs | 28 ++ .../System/Reflection/MemberInfoExtensions.cs | 5 +- .../Reflection/PropertyInfoExtensions.cs | 21 -- .../System/Text/StringBuilderExtensions.cs | 44 --- .../Generic/CollectionExtensionsTests.cs | 291 ++++++++++++++++-- .../System/DateTimeExtensionsTests.cs | 70 +++-- .../System/ExceptionExtensionsTests.cs | 82 +++++ .../Reflection/MemberInfoExtensionsTests.cs | 58 ++++ .../Reflection/MethodInfoExtensionsTests.cs | 87 ++++++ .../Text/StringBuilderExtensionsTest.cs | 119 ++++--- .../Entities/Blogs/IBlogsRepository.cs | 3 +- 16 files changed, 682 insertions(+), 253 deletions(-) create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.Core/System/LongExtensions.cs delete mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/PropertyInfoExtensions.cs create mode 100644 aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/ExceptionExtensionsTests.cs create mode 100644 aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MemberInfoExtensionsTests.cs create mode 100644 aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MethodInfoExtensionsTests.cs diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/GlobalUsings.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/GlobalUsings.cs index db552e04..744245fa 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/GlobalUsings.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/GlobalUsings.cs @@ -1,5 +1,6 @@ // Global using directives +global using System.ComponentModel; global using System.ComponentModel.DataAnnotations; global using System.Diagnostics; global using System.Globalization; diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Collections/Generic/CollectionExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Collections/Generic/CollectionExtensions.cs index c0714cab..a83642db 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Collections/Generic/CollectionExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Collections/Generic/CollectionExtensions.cs @@ -35,10 +35,10 @@ public static class CollectionExtensions public static void AddIfNotExist(this ICollection collection, T value, Func existFunc = null) { if (collection is null) throw new ArgumentNullException(); - var exists = existFunc == null ? collection!.Contains(value) : collection!.Any(existFunc); + var exists = existFunc == null ? collection.Contains(value) : collection.Any(existFunc); if (!exists) { - collection!.Add(value); + collection.Add(value); } } diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/DateTimeExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/DateTimeExtensions.cs index c4cc7aef..e3d481eb 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/DateTimeExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/DateTimeExtensions.cs @@ -37,38 +37,7 @@ public static class DateTimeExtensions }; return weeks.Contains(dateTime.DayOfWeek); } - - /// - /// 获取时间相对唯一字符串 - /// - /// - /// 是否使用毫秒 - /// - public static string ToUniqueString(this DateTime dateTime, bool millisecond = false) - { - var seconds = dateTime.Hour * 3600 + dateTime.Minute * 60 + dateTime.Second; - var value = $"{dateTime:yyyy}{dateTime.DayOfYear}{seconds}"; - if (millisecond) - { - return value + dateTime.ToString("fff"); - } - - return value; - } - - /// - /// 将时间转换为JS时间格式(Date.getTime()) - /// - /// - /// 是否使用毫秒 - public static string ToJsGetTime(this DateTime dateTime, bool millisecond = true) - { - var utc = dateTime.ToUniversalTime(); - var span = utc.Subtract(new DateTime(1970, 1, 1)); - return Math.Round(millisecond ? span.TotalMilliseconds : span.TotalSeconds).ToString(CultureInfo.InvariantCulture); - } - - + /// /// 将时间类型转成int类型. 例如 2021-09-01 => 20210901 /// @@ -89,7 +58,7 @@ public static class DateTimeExtensions /// /// 获取指定日期 当天的最大时间 - /// 例如 2021-09-10 11:22:33.123456 转换后 2021-09-10 23:59:59.9999999 + /// 例如 2021-09-10 11:22:33.123 转换后 2021-09-10 23:59:59.999 /// public static DateTime? ToCurrentDateMaxDateTime(this DateTime? dateTime) { @@ -98,11 +67,11 @@ public static class DateTimeExtensions /// /// 获取指定日期 当天的最大时间 - /// 例如 2021-09-10 11:22:33.123456 转换后 2021-09-10 23:59:59.9999999 + /// 例如 2021-09-10 11:22:33.123 转换后 2021-09-10 23:59:59.999 /// public static DateTime ToCurrentDateMaxDateTime(this DateTime dateTime) { - return dateTime.Date.AddDays(1).AddTicks(-1); + return dateTime.Date.AddDays(1).AddMilliseconds(-1); } /// @@ -110,7 +79,7 @@ public static class DateTimeExtensions /// public static DateTime? ToCurrentDateMinDateTime(this DateTime? dateTime) { - return dateTime?.Date.AddTicks(1); + return dateTime?.Date; } /// @@ -118,7 +87,7 @@ public static class DateTimeExtensions /// public static DateTime ToCurrentDateMinDateTime(this DateTime dateTime) { - return dateTime.Date.AddTicks(1); + return dateTime.Date; } /// @@ -138,55 +107,42 @@ public static class DateTimeExtensions /// /// 转为秒级时间戳 /// 时间 - /// 默认 TimeZoneInfo.Utc + /// + ///时间戳实际就是当前时间距离1970年1月1日0点0时0分0秒(转换成北京时间是1970年1月1日8点0时0分0秒)距离你要计算的时间的秒数或者毫秒数 一般来说:我们用的时间戳到秒的话是10位,到毫秒的话是13位 + /// /// - public static long ToSecondTimeStamp(this DateTime dateTime, TimeZoneInfo timeZoneInfo = null) + public static long ToUnixTimeSeconds(this DateTime dateTime) { - timeZoneInfo ??= TimeZoneInfo.Utc; - var dtStart = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0), timeZoneInfo); - long timeStamp = Convert.ToInt32((dateTime - dtStart).TotalSeconds); - return timeStamp; + return (new DateTimeOffset(dateTime)).ToUnixTimeSeconds(); } /// /// 转为秒级时间戳 /// 时间 - /// 默认 TimeZoneInfo.Utc /// - public static long? ToSecondTimeStamp(this DateTime? dateTime, TimeZoneInfo timeZoneInfo = null) + public static long? ToUnixTimeSeconds(this DateTime? dateTime) { if (!dateTime.HasValue) return null; - timeZoneInfo ??= TimeZoneInfo.Utc; - var dtStart = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0), timeZoneInfo); - long timeStamp = Convert.ToInt32((dateTime.Value - dtStart).TotalSeconds); - return timeStamp; + return (new DateTimeOffset(dateTime.Value)).ToUnixTimeSeconds(); } /// /// 转为毫秒级时间戳 /// 时间 - /// 默认 TimeZoneInfo.Utc /// - public static long ToMilliSecondTimeStamp(this DateTime dateTime, TimeZoneInfo timeZoneInfo = null) + public static long? ToUnixTimeMilliseconds(this DateTime dateTime) { - timeZoneInfo ??= TimeZoneInfo.Utc; - var dtStart = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0), timeZoneInfo); - var timeStamp = Convert.ToInt64((dateTime - dtStart).TotalMilliseconds); - return timeStamp; + return (new DateTimeOffset(dateTime)).ToUnixTimeMilliseconds(); } /// /// 转为毫秒级时间戳 /// 时间 - /// 默认 TimeZoneInfo.Utc /// - public static long? ToMilliSecondTimeStamp(this DateTime? dateTime, TimeZoneInfo timeZoneInfo = null) + public static long? ToUnixTimeMilliseconds(this DateTime? dateTime) { if (!dateTime.HasValue) return null; - timeZoneInfo ??= TimeZoneInfo.Utc; - var dtStart = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0), timeZoneInfo); - var timeStamp = Convert.ToInt64((dateTime.Value - dtStart).TotalMilliseconds); - return timeStamp; + return (new DateTimeOffset(dateTime.Value)).ToUnixTimeMilliseconds(); } /// diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/EnumExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/EnumExtensions.cs index 2f96211c..5ab9f1a8 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/EnumExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/EnumExtensions.cs @@ -1,5 +1,4 @@ using System.Collections.Specialized; -using System.ComponentModel; using System.Reflection; namespace System; diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/ExceptionExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/ExceptionExtensions.cs index 3b945f9b..dfe891f4 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/ExceptionExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/ExceptionExtensions.cs @@ -1,4 +1,5 @@ using System.Runtime.ExceptionServices; +using Volo.Abp.ExceptionHandling; namespace System; @@ -16,39 +17,27 @@ public static class ExceptionExtensions public static string FormatMessage(this Exception e, bool isHideStackTrace = false) { var sb = new StringBuilder(); - var count = 0; var appString = string.Empty; - while (e != null) + if (e == null) return sb.ToString(); + if (e is IHasErrorCode errorCodeException) { - if (count > 0) - { - appString += " "; - } - sb.AppendLine($"{appString}异常消息:{e.Message}"); - sb.AppendLine($"{appString}异常类型:{e.GetType().FullName}"); - sb.AppendLine($"{appString}异常方法:{(e.TargetSite == null ? null : e.TargetSite.Name)}"); - sb.AppendLine($"{appString}异常源:{e.Source}"); - if (!isHideStackTrace && e.StackTrace != null) - { - sb.AppendLine($"{appString}异常堆栈:{e.StackTrace}"); - } - if (e.InnerException != null) - { - sb.AppendLine($"{appString}内部异常:"); - count++; - e = e.InnerException; - } + sb.AppendLine($"{appString}异常Code:{errorCodeException.Code}"); } + + sb.AppendLine($"{appString}异常消息:{e.Message}"); + sb.AppendLine($"{appString}异常类型:{e.GetType().FullName}"); + sb.AppendLine($"{appString}异常方法:{(e.TargetSite == null ? null : e.TargetSite.Name)}"); + sb.AppendLine($"{appString}异常源:{e.Source}"); + if (!isHideStackTrace && e.StackTrace != null) + { + sb.AppendLine($"{appString}异常堆栈:{e.StackTrace}"); + } + + if (e.InnerException == null) return sb.ToString(); + sb.AppendLine($"{appString}内部异常:"); return sb.ToString(); } - /// - /// 将异常重新抛出 - /// - public static void ReThrow(this Exception exception) - { - ExceptionDispatchInfo.Capture(exception).Throw(); - } /// /// 如果条件成立,则抛出异常 diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/LongExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/LongExtensions.cs new file mode 100644 index 00000000..3c8190ac --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/LongExtensions.cs @@ -0,0 +1,28 @@ +using System.Collections.Specialized; +using System.Reflection; + +namespace System; + +/// +/// long的扩展辅助操作方法 +/// +public static class LongExtensions +{ + /// + /// 时间戳转本地时间-时间戳精确到秒 + /// + public static DateTime ToLocalTimeDateBySeconds(this long unix) + { + var dto = DateTimeOffset.FromUnixTimeSeconds(unix); + return dto.ToLocalTime().DateTime; + } + + /// + /// 时间戳转本地时间-时间戳精确到毫秒 + /// + public static DateTime ToLocalTimeDateByMilliseconds(this long unix) + { + var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix); + return dto.ToLocalTime().DateTime; + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/MemberInfoExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/MemberInfoExtensions.cs index f34de4b2..232a368c 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/MemberInfoExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/MemberInfoExtensions.cs @@ -1,13 +1,10 @@ -using System.ComponentModel; - -namespace System.Reflection; +namespace System.Reflection; /// /// 成员的扩展辅助操作方法 /// public static class MemberInfoExtensions { - /// /// 获取成员元数据的Description特性描述信息。 /// diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/PropertyInfoExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/PropertyInfoExtensions.cs deleted file mode 100644 index 001e4565..00000000 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Reflection/PropertyInfoExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace System.Reflection; - -/// -/// 属性的扩展辅助操作方法 -/// -public static class PropertyInfoExtensions -{ - /// - /// 返回当前属性信息是否为virtual - /// - public static bool IsVirtual(this PropertyInfo property) - { - var accessor = property.GetAccessors().FirstOrDefault(); - if (accessor == null) - { - return false; - } - - return accessor.IsVirtual && !accessor.IsFinal; - } -} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Text/StringBuilderExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Text/StringBuilderExtensions.cs index 00346bf6..6e878eef 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Text/StringBuilderExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.Core/System/Text/StringBuilderExtensions.cs @@ -197,48 +197,4 @@ public static class StringBuilderExtensions return new string(cs); } - - public static StringBuilder AppendLineWithControlChar(this StringBuilder stringBuilder, StringBuilder sb, string newLine) - { - if (stringBuilder is null) throw new ArgumentNullException(); - stringBuilder = AppendWithControlChar(stringBuilder, sb.ToString()); - return stringBuilder.Append(newLine); - } - - public static StringBuilder AppendLineWithControlChar(this StringBuilder stringBuilder, string str, string newLine) - { - if (stringBuilder is null) throw new ArgumentNullException(); - stringBuilder = AppendWithControlChar(stringBuilder, str); - return stringBuilder.Append(newLine); - } - - public static StringBuilder AppendWithControlChar(this StringBuilder stringBuilder, StringBuilder sb) - { - if (stringBuilder is null) throw new ArgumentNullException(); - return AppendWithControlChar(stringBuilder, sb.ToString()); - } - - public static StringBuilder AppendWithControlChar(this StringBuilder stringBuilder, string str) - { - if (str.Contains('\b')) - { - foreach (var c in str) - { - if (c == '\b') - { - stringBuilder.Length--; - } - else - { - stringBuilder.Append(c); - } - } - } - else - { - stringBuilder.Append(str); - } - - return stringBuilder; - } } \ No newline at end of file diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Collections/Generic/CollectionExtensionsTests.cs b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Collections/Generic/CollectionExtensionsTests.cs index a785cb46..a9dc70f8 100644 --- a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Collections/Generic/CollectionExtensionsTests.cs +++ b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Collections/Generic/CollectionExtensionsTests.cs @@ -3,34 +3,283 @@ public class CollectionExtensionsTests { [Fact] - public void AddIfNotExistTest() + public void AddIf_WithFlagTrue_ShouldAddItem() { - var numbers = new List() { 1, 2, 3 }; - numbers.AddIfNotExist(2); - numbers.Count(m => m == 2).ShouldBe(1); - numbers.AddIfNotExist(5); - numbers.Count(m => m == 5).ShouldBe(1); + // Arrange + var collection = new List(); - numbers = null; - Should.Throw(() => - { - numbers.AddIfNotExist(3); - }); + // Act + collection.AddIf(1, true); + + // Assert + collection.ShouldContain(1); + } + + [Fact] + public void AddIf_WithFlagFalse_ShouldNotAddItem() + { + // Arrange + var collection = new List(); + + // Act + collection.AddIf(1, false); + + // Assert + collection.ShouldBeEmpty(); + } + + [Fact] + public void AddIf_WithFuncReturningTrue_ShouldAddItem() + { + // Arrange + var collection = new List(); + Func func = () => true; + + // Act + collection.AddIf(1, func); + + // Assert + collection.ShouldContain(1); } [Fact] - public void AddIfNotNullTest() + public void AddIf_WithFuncReturningFalse_ShouldNotAddItem() { - var strings = new List() { "abc", "bcd", "cde" }; - strings.AddIfNotNull(null); - strings.Count.ShouldBe(3); - strings.AddIfNotNull("abc"); - strings.Count.ShouldBe(4); + // Arrange + var collection = new List(); + Func func = () => false; - strings = null; - Should.Throw(() => + // Act + collection.AddIf(1, func); + + // Assert + collection.ShouldBeEmpty(); + } + + [Fact] + public void AddIf_WithNullCollection_ShouldThrowArgumentNullException() + { + // Arrange + ICollection collection = null; + + // Act & Assert + Should.Throw(() => collection.AddIf(1, true)); + } + + + [Theory] + [InlineData(true, new int[] { 1, 2, 3 }, 4)] + [InlineData(false, new int[] { 1, 2, 3 }, 2)] + public void AddIf_WhenFuncReturnsTrue_AddsValueToCollection(bool exists, IEnumerable existingValues, int valueToAdd) + { + // Arrange + var collection = new List(existingValues); + var func = () => exists ? existingValues.Contains(valueToAdd) : !existingValues.Contains(valueToAdd); + + // Act + collection.AddIf(valueToAdd, func); + + // Assert + if (exists) { - strings.AddIfNotNull("abc"); - }); + collection.ShouldBe(existingValues); + } + else + { + collection.ShouldContain(valueToAdd); + } + } + + [Fact] + public void AddIfNotExist_WhenCollectionIsNull_ThrowsArgumentNullException() + { + // Arrange + ICollection collection = null; + var value = 42; + + // Act & Assert + Should.Throw(() => collection.AddIfNotExist(value)); + } + + [Fact] + public void AddIfNotExist_WhenValueExistsInCollection_AddsNothingToCollection() + { + // Arrange + var collection = new List { 1, 2, 3 }; + var valueToAdd = 2; + + // Act + collection.AddIfNotExist(valueToAdd); + + // Assert + collection.ShouldBe(new[] { 1, 2, 3 }); + } + + [Fact] + public void AddIfNotExist_WhenValueDoesNotExistInCollection_AddsValueToCollection() + { + // Arrange + var collection = new List { 1, 2, 3 }; + var valueToAdd = 4; + + // Act + collection.AddIfNotExist(valueToAdd); + + // Assert + collection.ShouldBe(new[] { 1, 2, 3, 4 }); + } + + [Fact] + public void AddIfNotExist_WhenExistFuncIsProvided_UsesExistFuncToDetermineIfValueExists() + { + // Arrange + ICollection collection = new List { "Foo", "Bar" }; + var valueToAdd = "baz"; + Func existFunc = s => s.StartsWith("b"); + + // Act + collection.AddIfNotExist(valueToAdd, existFunc); + + // Assert + collection.ShouldBe(new[] { "Foo", "Bar", "baz" }); + } + + [Fact] + public void AddIfNotNull_WhenCollectionIsNull_ThrowsArgumentNullException() + { + // Arrange + ICollection collection = null; + var valueToAdd = "Foo"; + + // Act & Assert + Should.Throw(() => collection.AddIfNotNull(valueToAdd)); + } + + [Fact] + public void AddIfNotNull_WhenValueIsNull_DoesNotAddValueToCollection() + { + // Arrange + var collection = new List(); + string valueToAdd = null; + + // Act + collection.AddIfNotNull(valueToAdd); + + // Assert + collection.ShouldBeEmpty(); + } + + [Fact] + public void AddIfNotNull_WhenValueIsNotNull_AddsValueToCollection() + { + // Arrange + var collection = new List(); + var valueToAdd = "Foo"; + + // Act + collection.AddIfNotNull(valueToAdd); + + // Assert + collection.ShouldBe(new[] { "Foo" }); + } + + [Fact] + public void GetOrAdd_Should_Return_Existing_Item() + { + // arrange + var collection = new List { "existing item" }; + var factory = new FakeFactory(); + + // act + var result = collection.GetOrAdd(item => item == "existing item", factory.Create); + + // assert + result.ShouldBe("existing item"); + collection.Count.ShouldBe(1); + } + + [Fact] + public void GetOrAdd_Should_Add_New_Item() + { + // arrange + var collection = new List(); + var factory = new FakeFactory(); + + // act + var result = collection.GetOrAdd(item => item == "new item", factory.Create); + + // assert + result.ShouldBe("new item"); + collection.ShouldContain(result); + } + + [Fact] + public void IsContinuous_WithNull_ReturnsFalse() + { + // Arrange + List numList = null; + + // Act + bool result = numList.IsContinuous(); + + // Assert + result.ShouldBeFalse(); + } + + [Fact] + public void IsContinuous_WithEmptyList_ReturnsFalse() + { + // Arrange + List numList = new List(); + + // Act + bool result = numList.IsContinuous(); + + // Assert + result.ShouldBeFalse(); + } + + [Fact] + public void IsContinuous_WithNonSequentialNumbers_ReturnsFalse() + { + // Arrange + List numList = new List { 1, 3, 5, 7 }; + + // Act + bool result = numList.IsContinuous(); + + // Assert + result.ShouldBeFalse(); + } + + [Fact] + public void IsContinuous_WithSequentialNumbers_ReturnsTrue() + { + // Arrange + List numList = new List { 1, 2, 3, 4, 5 }; + + // Act + bool result = numList.IsContinuous(); + + // Assert + result.ShouldBeTrue(); + } + + [Fact] + public void IsContinuous_WithReverseSequentialNumbers_ReturnsTrue() + { + // Arrange + List numList = new List { 5, 4, 3, 2, 1 }; + + // Act + bool result = numList.IsContinuous(); + + // Assert + result.ShouldBeTrue(); + } + + private class FakeFactory + { + public string Create() => "new item"; } } \ No newline at end of file diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/DateTimeExtensionsTests.cs b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/DateTimeExtensionsTests.cs index 6a567abf..057c9de6 100644 --- a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/DateTimeExtensionsTests.cs +++ b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/DateTimeExtensionsTests.cs @@ -3,48 +3,64 @@ public class DateTimeExtensionsTests { [Fact] - public void IsWeekendTest() + public void IsWeekend_ReturnsTrueForWeekends() { - var dt = new DateTime(2021, 4, 24); - dt.IsWeekend().ShouldBeTrue(); - dt = new DateTime(2021, 4, 25); - dt.IsWeekend().ShouldBeTrue(); - for (var i = 1; i <= 5; i++) - { - dt = new DateTime(2021, 4, 25 + i); - dt.IsWeekend().ShouldBeFalse(); - } + new DateTime(2021, 9, 11).IsWeekend().ShouldBeTrue(); // Saturday + new DateTime(2021, 9, 12).IsWeekend().ShouldBeTrue(); // Sunday } [Fact] - public void IsWeekdayTest() + public void IsWeekend_ReturnsFalseForWeekdays() { - var dt = new DateTime(2021, 4, 24); - dt.IsWeekday().ShouldBeFalse(); - dt = new DateTime(2021, 4, 25); - dt.IsWeekday().ShouldBeFalse(); - for (var i = 1; i <= 5; i++) - { - dt = new DateTime(2021, 4, 25 + i); - dt.IsWeekday().ShouldBeTrue(); - } + new DateTime(2021, 9, 13).IsWeekend().ShouldBeFalse(); // Monday + new DateTime(2021, 9, 14).IsWeekend().ShouldBeFalse(); // Tuesday + new DateTime(2021, 9, 15).IsWeekend().ShouldBeFalse(); // Wednesday + new DateTime(2021, 9, 16).IsWeekend().ShouldBeFalse(); // Thursday + new DateTime(2021, 9, 17).IsWeekend().ShouldBeFalse(); // Friday } + [Fact] - public void ToUniqueStringTest() + public void ToCurrentDateMinDateTime_ReturnsExpectedValue() { - var dt = new DateTime(2021, 4, 24,21,30,23); - dt.ToUniqueString().ShouldBe("202111477423"); - dt = dt.AddMilliseconds(-1); - dt.ToUniqueString(true).ShouldBe("202111477422999"); + var dateTime = new DateTime(2021, 9, 10, 11, 22, 33, 123); + dateTime.ToCurrentDateMinDateTime().ShouldBe(new DateTime(2021, 9, 10, 0, 0, 0)); + } + + + [Fact] + public void ToUnixTimeSeconds_ReturnsExpectedValue() + { + // Arrange + var dateTime = new DateTime(2021, 9, 15, 12, 34, 56); + + // Act + var timeStamp = dateTime.ToUnixTimeSeconds(); + + // Assert + timeStamp.ToLocalTimeDateBySeconds().ShouldBe(dateTime); } + [Fact] + public void ToUnixTimeMilliseconds_ReturnsExpectedValue() + { + // Arrange + var dateTime = new DateTime(2021, 9, 15, 12, 34, 56); + + // Act + var timeStamp = dateTime.ToUnixTimeMilliseconds(); + + // Assert + timeStamp.Value.ToLocalTimeDateByMilliseconds().ShouldBe(dateTime); + + } + [Fact] public void ToYyyyMMddTest() { var dt1 = new DateTime(2021, 9, 1); dt1.ToYyyyMmDd().ShouldBe(20210901); - + var dt2 = new DateTime(2020, 12, 31); dt2.ToYyyyMmDd().ShouldBe(20201231); } @@ -54,7 +70,7 @@ public class DateTimeExtensionsTests { var dt1 = new DateTime(2021, 9, 6); dt1.ToYyyyMm().ShouldBe(202109); - + var dt2 = new DateTime(2020, 12, 31); dt2.ToYyyyMm().ShouldBe(202012); } diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/ExceptionExtensionsTests.cs b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/ExceptionExtensionsTests.cs new file mode 100644 index 00000000..af68290e --- /dev/null +++ b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/ExceptionExtensionsTests.cs @@ -0,0 +1,82 @@ +using System.Text; + +namespace System; + +public class ExceptionExtensionsTests +{ + [Fact] + public void FormatMessage_ReturnsFormattedString() + { + // Arrange + var exception = new Exception("Test exception"); + exception.Data["CustomData"] = "Custom value"; + var isHideStackTrace = false; + var expectedMessage = new StringBuilder() + .AppendLine("异常消息:Test exception") + .AppendLine("异常类型:System.Exception") + .AppendLine("异常方法:") + .AppendLine("异常源:") + .AppendLine("异常堆栈: at YourNamespace.Tests.ExceptionExtensionsTests.FormatMessage_ReturnsFormattedString()") + .AppendLine("内部异常:") + .ToString(); + + // Act + var result = exception.FormatMessage(isHideStackTrace); + + // Assert + result.ShouldBe(expectedMessage); + } + + // [Fact] + // public void ReThrow_RethrowsException() + // { + // // Arrange + // var originalException = new Exception("Original exception"); + // + // // Act & Assert + // Should.Throw(() => originalException.ReThrow()); + // } + // + + [Fact] + public void ThrowIf_ThrowsExceptionIfConditionIsTrue() + { + // Arrange + var exception = new InvalidOperationException("Test exception"); + var isThrow = true; + + // Act & Assert + Should.Throw(() => exception.ThrowIf(isThrow)); + } + + [Fact] + public void ThrowIf_DoesNotThrowExceptionIfConditionIsFalse() + { + // Arrange + var exception = new InvalidOperationException("Test exception"); + var isThrow = false; + + // Act & Assert + exception.ThrowIf(isThrow); // Should not throw an exception + } + + [Fact] + public void ThrowIf_ThrowsExceptionIfConditionFunctionIsTrue() + { + // Arrange + var exception = new InvalidOperationException("Test exception"); + + // Act & Assert + Should.Throw(() => exception.ThrowIf(() => true)); + } + + [Fact] + public void ThrowIf_DoesNotThrowExceptionIfConditionFunctionIsFalse() + { + // Arrange + var exception = new InvalidOperationException("Test exception"); + + // Act & Assert + exception.ThrowIf(() => false); // Should not throw an exception + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MemberInfoExtensionsTests.cs b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MemberInfoExtensionsTests.cs new file mode 100644 index 00000000..30abd1cf --- /dev/null +++ b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MemberInfoExtensionsTests.cs @@ -0,0 +1,58 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace System.Reflection; + +public class MemberInfoExtensionsTests +{ + private class TestClass + { + [Description("Test property")] + public string TestProperty { get; set; } + + [DisplayName("Test method")] + public void TestMethod() {} + + [Display(Name = "Test field")] + public int TestField; + } + + [Fact] + public void GetDescription_ReturnsDescriptionAttribute_WhenExists() + { + // Arrange + var memberInfo = typeof(TestClass).GetProperty(nameof(TestClass.TestProperty)); + + // Act + var result = memberInfo.GetDescription(); + + // Assert + result.ShouldBe("Test property"); + } + + [Fact] + public void GetDescription_ReturnsDisplayNameAttribute_WhenDescriptionAttributeNotExists() + { + // Arrange + var memberInfo = typeof(TestClass).GetMethod(nameof(TestClass.TestMethod)); + + // Act + var result = memberInfo.GetDescription(); + + // Assert + result.ShouldBe("Test method"); + } + + [Fact] + public void GetDescription_ReturnsDisplayAttribute_WhenBothDescriptionAndDisplayNameAttributesNotExists() + { + // Arrange + var memberInfo = typeof(TestClass).GetField(nameof(TestClass.TestField)); + + // Act + var result = memberInfo.GetDescription(); + + // Assert + result.ShouldBe("Test field"); + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MethodInfoExtensionsTests.cs b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MethodInfoExtensionsTests.cs new file mode 100644 index 00000000..8a1ce4a4 --- /dev/null +++ b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Reflection/MethodInfoExtensionsTests.cs @@ -0,0 +1,87 @@ +namespace System.Reflection; + +public class MethodInfoExtensionsTests +{ + private abstract class BaseClass + { + public virtual void Method1() {} + + public virtual async Task Method2Async() { await Task.Delay(1); return 42; } + + public void Method3() {} + } + + private class DerivedClass : BaseClass + { + public override void Method1() {} + + public override async Task Method2Async() { await Task.Delay(1); return 43; } + + public new void Method3() {} + } + + [Fact] + public void IsAsync_ReturnsFalse_WhenReturnTypeIsNotTask() + { + // Arrange + var methodInfo = typeof(BaseClass).GetMethod(nameof(BaseClass.Method1)); + + // Act + var result = methodInfo.IsAsync(); + + // Assert + result.ShouldBeFalse(); + } + + [Fact] + public void IsAsync_ReturnsTrue_WhenReturnTypeIsTaskOfT() + { + // Arrange + var methodInfo = typeof(BaseClass).GetMethod(nameof(BaseClass.Method2Async)); + + // Act + var result = methodInfo.IsAsync(); + + // Assert + result.ShouldBeTrue(); + } + + [Fact] + public void IsOverridden_ReturnsFalse_WhenMethodIsNotOverridden() + { + // Arrange + var methodInfo = typeof(BaseClass).GetMethod(nameof(BaseClass.Method3)); + + // Act + var result = methodInfo.IsOverridden(); + + // Assert + result.ShouldBeFalse(); + } + + [Fact] + public void IsOverridden_ReturnsTrue_WhenMethodIsOverridden() + { + // Arrange + var methodInfo = typeof(DerivedClass).GetMethod(nameof(DerivedClass.Method1)); + + // Act + var result = methodInfo.IsOverridden(); + + // Assert + result.ShouldBeTrue(); + } + + [Fact] + public void IsOverridden_ReturnsFalse_WhenMethodIsHiddenByNew() + { + // Arrange + var methodInfo = typeof(DerivedClass).GetMethod(nameof(DerivedClass.Method3)); + + // Act + var result = methodInfo.IsOverridden(); + + // Assert + result.ShouldBeFalse(); + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Text/StringBuilderExtensionsTest.cs b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Text/StringBuilderExtensionsTest.cs index bc5cd65d..ff2382ad 100644 --- a/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Text/StringBuilderExtensionsTest.cs +++ b/aspnet-core/frameworks/test/Lion.AbpPro.Core.Tests/System/Text/StringBuilderExtensionsTest.cs @@ -1,58 +1,91 @@ -namespace System.Text; - -public class StringBuilderExtensionsTest +namespace System.Text { - [Fact] - public void TrimTest() + public class StringBuilderExtensionsTest { - var sb = new StringBuilder(" hello world "); - sb.Trim().ToString().ShouldBe("hello world"); - } - - [Fact] - public void TrimStartTest() - { - var sb = new StringBuilder(); - sb.TrimStart('a').ToString().ShouldBe(string.Empty); - - sb.Append("asdfgef"); - sb.TrimStart('a').ToString().ShouldBe("sdfgef"); - - sb.Insert(0, " "); - sb.TrimStart().ToString().ShouldBe("sdfgef"); + [Fact] + public void TrimStart_RemovesLeadingWhitespace() + { + var sb = new StringBuilder(" hello"); + sb.TrimStart(); + sb.ToString().ShouldBe("hello"); + } - sb.TrimStart("sdf").ToString().ShouldBe("gef"); + [Fact] + public void TrimStart_RemovesLeadingChar() + { + var sb = new StringBuilder("***hello"); + sb.TrimStart('*'); + sb.ToString().ShouldBe("hello"); + } - sb.TrimStart("gef").ToString().ShouldBe(string.Empty); - } + [Fact] + public void TrimStart_RemovesLeadingChars() + { + var sb = new StringBuilder("###hello"); + sb.TrimStart(new char[] { '#' }); + sb.ToString().ShouldBe("hello"); + } - [Fact] - public void TrimEndTest() - { - var sb = new StringBuilder("asdfgef"); + [Fact] + public void TrimStart_RemovesLeadingString() + { + var sb = new StringBuilder("world of warcraft"); + sb.TrimStart("world of"); + sb.ToString().ShouldBe(" warcraft"); + } - sb.TrimEnd((string)null).ToString().ShouldBe("asdfgef"); + [Fact] + public void TrimEnd_RemovesTrailingWhitespace() + { + var sb = new StringBuilder("world "); + sb.TrimEnd(); + sb.ToString().ShouldBe("world"); + } - sb.TrimEnd('a').ToString().ShouldBe("asdfgef"); + [Fact] + public void TrimEnd_RemovesTrailingChar() + { + var sb = new StringBuilder("hello***"); + sb.TrimEnd('*'); + sb.ToString().ShouldBe("hello"); + } - sb.TrimEnd('f').ToString().ShouldBe("asdfge"); + [Fact] + public void TrimEnd_RemovesTrailingChars() + { + var sb = new StringBuilder("hello###"); + sb.TrimEnd(new char[] { '#' }); + sb.ToString().ShouldBe("hello"); + } - sb.Append(" "); - sb.TrimEnd().ToString().ShouldBe("asdfge"); + [Fact] + public void TrimEnd_RemovesTrailingString() + { + var sb = new StringBuilder("world of warcraft"); + sb.TrimEnd("of warcraft"); + sb.ToString().ShouldBe("world "); + } - sb.TrimEnd(new[] { 'g', 'e' }).ToString().ShouldBe("asdf"); - sb.TrimEnd("asdf").ToString().ShouldBe(string.Empty); - } + [Fact] + public void Trim_RemovesLeadingAndTrailingWhitespace() + { + var sb = new StringBuilder(" foo "); + sb.Trim(); + sb.ToString().ShouldBe("foo"); + } - [Fact] - public void SubStringTest() - { - var sb = new StringBuilder("asdfgef"); - Should.Throw(() => + [Fact] + public void Substring_ReturnsSubstringWithCorrectLength() { - sb.SubString(0, 8); - }); - sb.SubString(0, 3).ToString().ShouldBe("asd"); + var sb = new StringBuilder("abcdefg"); + sb.SubString(1, 3).ShouldBe("bcd"); + } + [Fact] + public void Substring_ThrowsExceptionWhenStartPlusLengthIsGreaterThanLength() + { + var sb = new StringBuilder("abcdefg"); + Should.Throw(() => sb.SubString(2, 6)); + } } } \ No newline at end of file diff --git a/aspnet-core/frameworks/test/Lion.AbpPro.EntityFrameworkCore.Mysql.Tests/Entities/Blogs/IBlogsRepository.cs b/aspnet-core/frameworks/test/Lion.AbpPro.EntityFrameworkCore.Mysql.Tests/Entities/Blogs/IBlogsRepository.cs index 0cf3cbf5..c575a337 100644 --- a/aspnet-core/frameworks/test/Lion.AbpPro.EntityFrameworkCore.Mysql.Tests/Entities/Blogs/IBlogsRepository.cs +++ b/aspnet-core/frameworks/test/Lion.AbpPro.EntityFrameworkCore.Mysql.Tests/Entities/Blogs/IBlogsRepository.cs @@ -1,7 +1,6 @@ -using Lion.AbpPro.EntityFrameworkCore.Tests.Entities.Blogs; using Volo.Abp.Domain.Repositories; -namespace Lion.AbpPro.EntityFrameworkCore.Tests.Blogs; +namespace Lion.AbpPro.EntityFrameworkCore.Tests.Entities.Blogs; public interface IBlogRepository : IBasicRepository {