test(diagram): DiagramLayoutService golden 用例
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
package com.yunhai.flowcenter.service;
|
||||
|
||||
import com.yunhai.flowcenter.engine.FlowDefModel;
|
||||
import com.yunhai.flowcenter.model.FlowModels;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* 布局单源 golden 用例(2026-10-03 三视图统一):PNG 与 DiagramVo.positions 共同消费这份几何。
|
||||
* 数值断言 ±1 容差(int 除法);关系断言(列距/居中/归零)与常量解耦,防调参误报。
|
||||
*/
|
||||
class DiagramLayoutServiceTest {
|
||||
|
||||
private final DiagramLayoutService service = new DiagramLayoutService();
|
||||
|
||||
private FlowModels.NodeVo node(String id, String type) {
|
||||
FlowModels.NodeVo n = new FlowModels.NodeVo();
|
||||
n.setId(id);
|
||||
n.setType(type);
|
||||
n.setLabel(id);
|
||||
return n;
|
||||
}
|
||||
|
||||
private FlowModels.EdgeVo edge(String from, String to) {
|
||||
FlowModels.EdgeVo e = new FlowModels.EdgeVo();
|
||||
e.setFrom(from);
|
||||
e.setTo(to);
|
||||
return e;
|
||||
}
|
||||
|
||||
private Map<String, int[]> layout(List<FlowModels.NodeVo> nodes, FlowModels.EdgeVo... edges) {
|
||||
return service.layout(nodes, new ArrayList<>(Arrays.asList(edges)));
|
||||
}
|
||||
|
||||
private int cy(int[] b) {
|
||||
return b[1] + b[3] / 2;
|
||||
}
|
||||
|
||||
@Test
|
||||
void linear_xPitchByColumn_andZeroMin() {
|
||||
List<FlowModels.NodeVo> nodes = new ArrayList<>(Arrays.asList(
|
||||
node("start", FlowDefModel.TYPE_START),
|
||||
node("a", FlowDefModel.TYPE_APPROVAL),
|
||||
node("b", FlowDefModel.TYPE_APPROVAL),
|
||||
node("end", FlowDefModel.TYPE_END)));
|
||||
Map<String, int[]> box = layout(nodes, edge("start", "a"), edge("a", "b"), edge("b", "end"));
|
||||
for (FlowModels.NodeVo n : nodes) {
|
||||
assertNotNull(box.get(n.getId()), "缺坐标:" + n.getId());
|
||||
}
|
||||
// 同宽节点(审批→审批)x 差 = 列距 SLOT_W+GAP_X(±1 容差)
|
||||
assertEquals(DiagramLayoutService.SLOT_W + DiagramLayoutService.GAP_X, box.get("b")[0] - box.get("a")[0], 1);
|
||||
// 归零:全部坐标非负且最小 x/y 为 0
|
||||
int minX = Integer.MAX_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
for (int[] b : box.values()) {
|
||||
assertTrue(b[0] >= 0 && b[1] >= 0);
|
||||
minX = Math.min(minX, b[0]);
|
||||
minY = Math.min(minY, b[1]);
|
||||
}
|
||||
assertEquals(0, minX);
|
||||
assertEquals(0, minY);
|
||||
}
|
||||
|
||||
@Test
|
||||
void conditionBranches_sameColumnBlockVerticallyCentered() {
|
||||
List<FlowModels.NodeVo> nodes = new ArrayList<>(Arrays.asList(
|
||||
node("start", FlowDefModel.TYPE_START),
|
||||
node("c", FlowDefModel.TYPE_CONDITION),
|
||||
node("a", FlowDefModel.TYPE_APPROVAL),
|
||||
node("b", FlowDefModel.TYPE_APPROVAL),
|
||||
node("end", FlowDefModel.TYPE_END)));
|
||||
Map<String, int[]> box = layout(nodes,
|
||||
edge("start", "c"), edge("c", "a"), edge("c", "b"), edge("a", "end"), edge("b", "end"));
|
||||
// 两分支同列不同行,列块垂直居中:两盒中心均值 ≈ 内容区中线(单行列的中心同值)
|
||||
assertEquals(box.get("a")[0], box.get("b")[0]);
|
||||
assertTrue(box.get("a")[1] != box.get("b")[1]);
|
||||
assertEquals(cy(box.get("c")), (cy(box.get("a")) + cy(box.get("b"))) / 2, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void parallelGroup_splitAndJoinShareCenterline() {
|
||||
List<FlowModels.NodeVo> nodes = new ArrayList<>(Arrays.asList(
|
||||
node("start", FlowDefModel.TYPE_START),
|
||||
node("s", FlowDefModel.TYPE_PARALLEL_SPLIT),
|
||||
node("a", FlowDefModel.TYPE_APPROVAL),
|
||||
node("b", FlowDefModel.TYPE_APPROVAL),
|
||||
node("j", FlowDefModel.TYPE_PARALLEL_JOIN),
|
||||
node("end", FlowDefModel.TYPE_END)));
|
||||
Map<String, int[]> box = layout(nodes,
|
||||
edge("start", "s"), edge("s", "a"), edge("s", "b"),
|
||||
edge("a", "j"), edge("b", "j"), edge("j", "end"));
|
||||
// split 与 join 同一水平中线,且即两分支的对称轴(centerParallelGroups 生效)
|
||||
assertEquals(cy(box.get("s")), cy(box.get("j")), 1);
|
||||
assertEquals(cy(box.get("s")), (cy(box.get("a")) + cy(box.get("b"))) / 2, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nestedParallel_groupsCentered_noNegativeY() {
|
||||
List<FlowModels.NodeVo> nodes = new ArrayList<>(Arrays.asList(
|
||||
node("start", FlowDefModel.TYPE_START),
|
||||
node("os", FlowDefModel.TYPE_PARALLEL_SPLIT),
|
||||
node("is", FlowDefModel.TYPE_PARALLEL_SPLIT),
|
||||
node("c", FlowDefModel.TYPE_APPROVAL),
|
||||
node("p", FlowDefModel.TYPE_APPROVAL),
|
||||
node("q", FlowDefModel.TYPE_APPROVAL),
|
||||
node("ij", FlowDefModel.TYPE_PARALLEL_JOIN),
|
||||
node("oj", FlowDefModel.TYPE_PARALLEL_JOIN),
|
||||
node("end", FlowDefModel.TYPE_END)));
|
||||
Map<String, int[]> box = layout(nodes,
|
||||
edge("start", "os"),
|
||||
edge("os", "is"), edge("os", "c"),
|
||||
edge("is", "p"), edge("is", "q"),
|
||||
edge("p", "ij"), edge("q", "ij"),
|
||||
edge("ij", "oj"), edge("c", "oj"),
|
||||
edge("oj", "end"));
|
||||
// 内层组:is 与 {p,q} 居中;外层组:os/oj 同中线即分支对称轴
|
||||
assertEquals(cy(box.get("is")), (cy(box.get("p")) + cy(box.get("q"))) / 2, 1);
|
||||
assertEquals(cy(box.get("os")), cy(box.get("oj")), 1);
|
||||
// 全图无 y<0(centerParallelGroups 末段抬回)
|
||||
for (int[] b : box.values()) {
|
||||
assertTrue(b[1] >= 0, "出现负 y:" + b[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cycle_defensive_fallbackLevelStillPositionsAllNodes() {
|
||||
List<FlowModels.NodeVo> nodes = new ArrayList<>(Arrays.asList(
|
||||
node("start", FlowDefModel.TYPE_START),
|
||||
node("a", FlowDefModel.TYPE_APPROVAL),
|
||||
node("b", FlowDefModel.TYPE_APPROVAL)));
|
||||
Map<String, int[]> box = assertDoesNotThrow(() -> layout(nodes,
|
||||
edge("start", "a"), edge("a", "b"), edge("b", "a")));
|
||||
// 环兜底:不抛异常,所有节点都有坐标
|
||||
for (FlowModels.NodeVo n : nodes) {
|
||||
assertNotNull(box.get(n.getId()), "缺坐标:" + n.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user