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);
}
}
}