暂存提交

This commit is contained in:
2026-08-19 16:24:02 +08:00
parent f5c4bf130a
commit 6acb6178da
354 changed files with 25000 additions and 198 deletions
@@ -0,0 +1,98 @@
package com.baiyue.warehouse.schema;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SchemaChineseCommentContractTest {
private static final Pattern TABLE = Pattern.compile(
"(?is)CREATE\\s+TABLE\\s+IF\\s+NOT\\s+EXISTS\\s+(wh_[a-z0-9_]+)"
+ "\\s*\\((.*?)\\)\\s*ENGINE\\s*=\\s*InnoDB\\s+COMMENT\\s*=\\s*'([^']*)'\\s*;");
private static final Pattern CHINESE = Pattern.compile("[\\u4e00-\\u9fff]");
@Test
void allWarehouseTablesAndColumnsHaveChineseCommentsAndMigrationCoverage() throws Exception {
String baseline = Files.readString(
Path.of("src", "main", "resources", "db", "warehouse.sql"), StandardCharsets.UTF_8);
String incremental = Files.readString(
Path.of("..", "scripts", "db", "incremental.sql"), StandardCharsets.UTF_8);
List<TableDefinition> tables = parseAndAssert(baseline, "仓储基线 SQL");
assertEquals(7, tables.size(), "仓储表数量变化时必须同步表索引和备注迁移");
parseAndAssert(incremental, "统一增量 SQL");
int marker = incremental.indexOf("2026-08-18 / 025 Chinese table and column comments");
assertTrue(marker >= 0, "统一增量 SQL 缺少 025 中文备注迁移");
String migration = incremental.substring(marker);
for (TableDefinition table : tables) {
assertTrue(migration.contains("table_name='" + table.name() + "'"),
"025 备注迁移缺少表: " + table.name());
for (String column : table.columns()) {
assertTrue(migration.contains("table_name='" + table.name()
+ "' AND column_name='" + column + "'"),
"025 备注迁移缺少字段: " + table.name() + "." + column);
}
}
}
private static List<TableDefinition> parseAndAssert(String sql, String source) {
List<TableDefinition> tables = new ArrayList<>();
Matcher matcher = TABLE.matcher(sql);
while (matcher.find()) {
String table = matcher.group(1);
assertTrue(CHINESE.matcher(matcher.group(3)).find(), source + " 表备注必须包含中文: " + table);
List<String> columns = new ArrayList<>();
for (String definition : splitTopLevel(matcher.group(2))) {
String normalized = definition.stripLeading().toUpperCase();
if (normalized.matches("^(PRIMARY|UNIQUE|KEY|CONSTRAINT|FOREIGN|CHECK)\\b.*")) {
continue;
}
String column = definition.stripLeading().split("\\s+", 2)[0].replace("`", "");
columns.add(column);
assertTrue(Pattern.compile("(?is)\\bCOMMENT\\s+'[^']*[\\u4e00-\\u9fff][^']*'")
.matcher(definition).find(),
source + " 字段备注必须包含中文: " + table + "." + column);
}
assertFalse(columns.isEmpty(), source + " 表定义没有字段: " + table);
tables.add(new TableDefinition(table, columns));
}
assertFalse(tables.isEmpty(), source + " 未解析到仓储表");
return tables;
}
private static List<String> splitTopLevel(String body) {
List<String> definitions = new ArrayList<>();
int start = 0;
int parentheses = 0;
boolean quoted = false;
for (int i = 0; i < body.length(); i++) {
char current = body.charAt(i);
if (current == '\'' && (i == 0 || body.charAt(i - 1) != '\\')) {
quoted = !quoted;
} else if (!quoted && current == '(') {
parentheses++;
} else if (!quoted && current == ')') {
parentheses--;
} else if (!quoted && parentheses == 0 && current == ',') {
definitions.add(body.substring(start, i).trim());
start = i + 1;
}
}
definitions.add(body.substring(start).trim());
return definitions.stream().filter(value -> !value.isEmpty()).toList();
}
private record TableDefinition(String name, List<String> columns) {
}
}
@@ -0,0 +1,24 @@
package com.baiyue.warehouse.schema;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
class WarehouseResourceLockSchemaTest {
@Test
void schemaContainsIdempotentResourceLockContract() throws IOException {
String sql;
try (var stream = getClass().getResourceAsStream("/db/warehouse.sql")) {
assertThat(stream).isNotNull();
sql = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
}
assertThat(sql).contains("CREATE TABLE IF NOT EXISTS wh_resource_lock");
assertThat(sql).contains("UNIQUE KEY uk_resource_lock_reservation (customer_id, reservation_key)");
assertThat(sql).contains("KEY idx_resource_lock_pallet (customer_id, warehouse_id, pallet_id, status)");
assertThat(sql).contains("KEY idx_resource_lock_location (customer_id, warehouse_id, location_id, status)");
}
}