using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; using YLErp.DBModels; using YLErp.Helpers; using System.Collections.Generic; using System.Linq; namespace YLErp.Helpers.Tests { /// /// 需求①:交易提交进入审批流程时的「起点触发条件跳过」测试。 /// 场景:交易一进来,若节点1、2配置的触发条件均不满足,应直接从节点3开始审核; /// 若全部节点都不满足,则直接审批通过(无需任何审核)。 /// [TestClass] public class TriggerNodeSkipTests { /// 构造一个审批节点:order + 可选的触发条件JSON。 private static approvalprocess Node(int order, string triggerCondition = null) { return new approvalprocess { order = order, node = 0, triggerCondition = triggerCondition }; } /// 构造"期初名义本金 > 阈值"的触发条件JSON。 private static string InitialNotionalGt(double threshold) { return JsonConvert.SerializeObject(new ConditionExpressionConfig { tokens = new List { new ConditionToken { type = "condition", condition = new ConditionItem { field = "initialNotional", op = "gt", value = threshold } } } }); } private static ConditionContext Ctx(double initialNotional) { return new ConditionContext { Trade = new trade { OriginalStockEqvNotional = initialNotional } }; } [TestMethod] public void StartNode_NoTrigger_ReturnsStartDirectly() { // 节点1无触发条件 → 直接返回节点1 var nodes = new List { Node(1), Node(2), Node(3) }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[0], Ctx(500)); Assert.IsNotNull(result); Assert.AreEqual(1, result.order); } [TestMethod] public void StartNode_TriggerSatisfied_ReturnsStart() { // 节点1触发条件">100",交易期初200满足 → 返回节点1 var nodes = new List { Node(1, InitialNotionalGt(100)), Node(2), Node(3) }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[0], Ctx(200)); Assert.IsNotNull(result); Assert.AreEqual(1, result.order); } [TestMethod] public void StartNode_TriggerNotSatisfied_SkipsToNextSatisfied() { // 节点1触发">100",节点2触发">500",交易期初200 // → 节点1不满足(200>100满足? 满足)... 重新设计:节点1触发">1000",200不满足;节点2无触发 → 返回节点2 var nodes = new List { Node(1, InitialNotionalGt(1000)), // 200 不满足 >1000 Node(2), // 无触发条件 Node(3) }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[0], Ctx(200)); Assert.IsNotNull(result); Assert.AreEqual(2, result.order); } [TestMethod] public void AllStartNodesNotSatisfied_ReturnsNull_DirectlyApproved() { // 节点1、2、3都有触发条件,交易都不满足 → 返回null(表示直接审批通过) var nodes = new List { Node(1, InitialNotionalGt(1000)), // 200 不满足 Node(2, InitialNotionalGt(5000)), // 200 不满足 Node(3, InitialNotionalGt(10000)) // 200 不满足 }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[0], Ctx(200)); Assert.IsNull(result); } [TestMethod] public void SkipMultipleNodes_LandsOnThird() { // 节点1、2都不满足,节点3无触发 → 返回节点3 // 模拟"A默认审核、B>100W再审核、C>=500W再审核"中,小额交易跳过B、C直达... 实际应停在满足的节点 var nodes = new List { Node(1, InitialNotionalGt(1000000)), // 50W 不满足 Node(2, InitialNotionalGt(2000000)), // 50W 不满足 Node(3) // 无触发条件(兜底审核) }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[0], Ctx(500000)); Assert.IsNotNull(result); Assert.AreEqual(3, result.order); } [TestMethod] public void SatisfiedAtSecondNode_StopsThere() { // 节点1触发">1000"不满足,节点2触发">100"满足 → 返回节点2(不会继续到节点3) var nodes = new List { Node(1, InitialNotionalGt(1000)), // 200 不满足 Node(2, InitialNotionalGt(100)), // 200 满足 Node(3, InitialNotionalGt(50)) // 不会走到这 }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[0], Ctx(200)); Assert.IsNotNull(result); Assert.AreEqual(2, result.order); } [TestMethod] public void StartFromMiddleNode_Works() { // 起点不是节点1(如分支调整后从节点2开始),从节点2起判断 var nodes = new List { Node(1, InitialNotionalGt(1000)), Node(2, InitialNotionalGt(1000)), // 200 不满足 Node(3) // 无触发 }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, nodes[1], Ctx(200)); Assert.IsNotNull(result); Assert.AreEqual(3, result.order); } [TestMethod] public void NullStart_ReturnsNull() { var nodes = new List { Node(1) }; var result = ConditionEvaluator.FindFirstTriggeredNode(nodes, null, Ctx(500)); Assert.IsNull(result); } } }