using FsCheck; using FsCheck.Xunit; using Xunit; using XiangYi.Application.Services; using XiangYi.Core.Enums; namespace XiangYi.Application.Tests.Services; /// /// AdminProfileAuditService属性测试 /// public class AdminProfileAuditServicePropertyTests { /// /// **Feature: backend-api, Property 24: 资料审核状态流转** /// **Validates: Requirements 14.1, 14.3, 14.4, 14.5** /// /// *For any* 用户资料, 状态应从"待审核"流转到"已通过"或"已拒绝", /// 且只有"已通过"状态的资料才能在列表展示 /// /// 此测试验证:从待审核状态可以流转到已通过或已拒绝 /// [Property(MaxTest = 100)] public Property StatusTransition_FromPending_ShouldAllowApproveOrReject() { // Generate target status (Approved or Rejected) var targetStatusArb = Gen.Elements( (int)AuditStatus.Approved, (int)AuditStatus.Rejected); return Prop.ForAll( targetStatusArb.ToArbitrary(), targetStatus => { // Act var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( (int)AuditStatus.Pending, targetStatus); // Assert - From Pending, should allow transition to Approved or Rejected return isValid; }); } /// /// 状态流转 - 从待审核不能流转到待审核 /// [Fact] public void StatusTransition_FromPending_ToPending_ShouldBeInvalid() { var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( (int)AuditStatus.Pending, (int)AuditStatus.Pending); Assert.False(isValid); } /// /// 状态流转 - 从已通过不能流转到任何状态 /// [Property(MaxTest = 100)] public Property StatusTransition_FromApproved_ShouldNotAllowAnyTransition() { // Generate any target status var targetStatusArb = Gen.Elements( (int)AuditStatus.Pending, (int)AuditStatus.Approved, (int)AuditStatus.Rejected); return Prop.ForAll( targetStatusArb.ToArbitrary(), targetStatus => { // Act var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( (int)AuditStatus.Approved, targetStatus); // Assert - From Approved, should not allow any transition return !isValid; }); } /// /// 状态流转 - 从已拒绝可以流转到已通过(重新审核通过) /// [Fact] public void StatusTransition_FromRejected_ToApproved_ShouldBeValid() { var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( (int)AuditStatus.Rejected, (int)AuditStatus.Approved); Assert.True(isValid); } /// /// 状态流转 - 从已拒绝可以流转到已拒绝(更新拒绝原因) /// [Fact] public void StatusTransition_FromRejected_ToRejected_ShouldBeValid() { var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( (int)AuditStatus.Rejected, (int)AuditStatus.Rejected); Assert.True(isValid); } /// /// 状态流转 - 从已拒绝不能流转到待审核 /// [Fact] public void StatusTransition_FromRejected_ToPending_ShouldBeInvalid() { var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( (int)AuditStatus.Rejected, (int)AuditStatus.Pending); Assert.False(isValid); } /// /// 状态流转 - 任何状态都不能手动流转到待审核 /// [Property(MaxTest = 100)] public Property StatusTransition_ToPending_ShouldAlwaysBeInvalid() { // Generate any current status var currentStatusArb = Gen.Elements( (int)AuditStatus.Pending, (int)AuditStatus.Approved, (int)AuditStatus.Rejected); return Prop.ForAll( currentStatusArb.ToArbitrary(), currentStatus => { // Act var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( currentStatus, (int)AuditStatus.Pending); // Assert - Should never allow transition to Pending return !isValid; }); } /// /// 列表展示 - 只有已通过状态的资料才能在列表展示 /// [Property(MaxTest = 100)] public Property CanDisplayInList_OnlyApprovedShouldBeDisplayable() { // Generate any audit status var auditStatusArb = Gen.Elements( (int)AuditStatus.Pending, (int)AuditStatus.Approved, (int)AuditStatus.Rejected); return Prop.ForAll( auditStatusArb.ToArbitrary(), auditStatus => { // Act var canDisplay = AdminProfileAuditService.CanDisplayInList(auditStatus); // Assert - Only Approved status should be displayable var expectedResult = auditStatus == (int)AuditStatus.Approved; return canDisplay == expectedResult; }); } /// /// 列表展示 - 待审核状态不能展示 /// [Fact] public void CanDisplayInList_Pending_ShouldNotBeDisplayable() { var canDisplay = AdminProfileAuditService.CanDisplayInList((int)AuditStatus.Pending); Assert.False(canDisplay); } /// /// 列表展示 - 已拒绝状态不能展示 /// [Fact] public void CanDisplayInList_Rejected_ShouldNotBeDisplayable() { var canDisplay = AdminProfileAuditService.CanDisplayInList((int)AuditStatus.Rejected); Assert.False(canDisplay); } /// /// 列表展示 - 已通过状态可以展示 /// [Fact] public void CanDisplayInList_Approved_ShouldBeDisplayable() { var canDisplay = AdminProfileAuditService.CanDisplayInList((int)AuditStatus.Approved); Assert.True(canDisplay); } /// /// 状态流转完整性 - 从待审核到已通过或已拒绝的流转应该是完整的 /// [Property(MaxTest = 100)] public Property StatusTransition_CompleteWorkflow_ShouldBeValid() { // Generate a sequence of valid transitions var workflowArb = Gen.Elements( new[] { (int)AuditStatus.Pending, (int)AuditStatus.Approved }, new[] { (int)AuditStatus.Pending, (int)AuditStatus.Rejected }, new[] { (int)AuditStatus.Pending, (int)AuditStatus.Rejected, (int)AuditStatus.Approved }, new[] { (int)AuditStatus.Pending, (int)AuditStatus.Rejected, (int)AuditStatus.Rejected }); return Prop.ForAll( workflowArb.ToArbitrary(), workflow => { // Verify each transition in the workflow is valid for (int i = 0; i < workflow.Length - 1; i++) { var isValid = AdminProfileAuditService.IsValidStatusTransitionStatic( workflow[i], workflow[i + 1]); if (!isValid) return false; } return true; }); } /// /// 状态流转 - 无效状态值应该被拒绝 /// [Property(MaxTest = 100)] public Property StatusTransition_InvalidStatusValues_ShouldBeRejected() { // Generate invalid status values (outside 0, 1, 2) var invalidStatusArb = Gen.Choose(-10, 10) .Where(s => s != 0 && s != 1 && s != 2); var validStatusArb = Gen.Elements(0, 1, 2); return Prop.ForAll( invalidStatusArb.ToArbitrary(), validStatusArb.ToArbitrary(), (invalidStatus, validStatus) => { // Act - Invalid current status var isValid1 = AdminProfileAuditService.IsValidStatusTransitionStatic( invalidStatus, validStatus); // Act - Invalid target status var isValid2 = AdminProfileAuditService.IsValidStatusTransitionStatic( validStatus, invalidStatus); // Assert - Both should be invalid return !isValid1 && !isValid2; }); } }