From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-flowable/jnpf-flowable-biz/src/test/java/jnpf/flowable/util/FlowStatusEventOrderChecks.java |   99 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 99 insertions(+), 0 deletions(-)

diff --git a/jnpf-flowable/jnpf-flowable-biz/src/test/java/jnpf/flowable/util/FlowStatusEventOrderChecks.java b/jnpf-flowable/jnpf-flowable-biz/src/test/java/jnpf/flowable/util/FlowStatusEventOrderChecks.java
new file mode 100644
index 0000000..064b41a
--- /dev/null
+++ b/jnpf-flowable/jnpf-flowable-biz/src/test/java/jnpf/flowable/util/FlowStatusEventOrderChecks.java
@@ -0,0 +1,99 @@
+package jnpf.flowable.util;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * 娴佺▼鐘舵�佸洖鍐欏繀椤诲厛浜庝笟鍔′簨浠剁殑婧愮爜绾у洖褰掓鏌ャ��
+ */
+public class FlowStatusEventOrderChecks {
+
+    private static final Path REPOSITORY_ROOT = Paths.get("").toAbsolutePath().normalize();
+
+    public static void main(String[] args) throws IOException {
+        String operatorUtil = read(
+                "jnpf-flowable/jnpf-flowable-biz/src/main/java/jnpf/flowable/util/OperatorUtil.java");
+        String taskController = read(
+                "jnpf-flowable/jnpf-flowable-controller/src/main/java/jnpf/flowable/controller/TaskController.java");
+        String operatorController = read(
+                "jnpf-flowable/jnpf-flowable-controller/src/main/java/jnpf/flowable/controller/OperatorController.java");
+        String autoAuditJob = read(
+                "jnpf-flowable/jnpf-flowable-biz/src/main/java/jnpf/flowable/job/AutoAuditJob.java");
+
+        String queuedEvent = extractMethod(operatorUtil, "public void handleTaskStatusThenEvent()");
+        requireOrder(queuedEvent, "handleTaskStatus();", "handleEvent();",
+                "queued events must run after form flow-state synchronization");
+
+        String directEvent = extractMethod(operatorUtil,
+                "public void handleTaskStatusThenEvent(FlowModel flowModel, Integer eventStatus)");
+        requireOrder(directEvent, "handleTaskStatus();", "flowUtil.event(flowModel, eventStatus);",
+                "direct events must run after form flow-state synchronization");
+
+        requireCount(operatorUtil, "handleEvent();", 1,
+                "OperatorUtil callers must use the status-then-event entry point");
+        forbid(taskController, "operatorUtil.handleEvent();",
+                "TaskController must not dispatch queued events directly");
+        forbid(taskController, "flowUtil.event(",
+                "TaskController must not dispatch direct events without state synchronization");
+        forbid(operatorController, "operatorUtil.handleEvent();",
+                "OperatorController must not dispatch queued events directly");
+        forbid(operatorController, "flowUtil.event(",
+                "OperatorController must not dispatch direct events without state synchronization");
+        forbid(autoAuditJob, "operatorUtil.handleEvent();",
+                "AutoAuditJob must not dispatch queued events directly");
+    }
+
+    private static String read(String relativePath) throws IOException {
+        return new String(Files.readAllBytes(REPOSITORY_ROOT.resolve(relativePath)), StandardCharsets.UTF_8);
+    }
+
+    private static String extractMethod(String source, String marker) {
+        int start = source.indexOf(marker);
+        if (start < 0) {
+            return "";
+        }
+        int bodyStart = source.indexOf('{', start);
+        int depth = 0;
+        for (int index = bodyStart; index < source.length(); index++) {
+            char current = source.charAt(index);
+            if (current == '{') {
+                depth++;
+            } else if (current == '}') {
+                depth--;
+                if (depth == 0) {
+                    return source.substring(start, index + 1);
+                }
+            }
+        }
+        return "";
+    }
+
+    private static void requireOrder(String source, String first, String second, String message) {
+        int firstIndex = source.indexOf(first);
+        int secondIndex = source.indexOf(second);
+        if (firstIndex < 0 || secondIndex < 0 || firstIndex >= secondIndex) {
+            throw new AssertionError(message);
+        }
+    }
+
+    private static void requireCount(String source, String value, int expected, String message) {
+        int count = 0;
+        int index = 0;
+        while ((index = source.indexOf(value, index)) >= 0) {
+            count++;
+            index += value.length();
+        }
+        if (count != expected) {
+            throw new AssertionError(message + ": expected=" + expected + ", actual=" + count);
+        }
+    }
+
+    private static void forbid(String source, String forbidden, String message) {
+        if (source.contains(forbidden)) {
+            throw new AssertionError(message);
+        }
+    }
+}

--
Gitblit v1.8.0