package jnpf.elnMapper;
|
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.Version;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import jnpf.elnEntity.template.ElnTemplateBindingEntity;
|
import jnpf.elnEntity.template.ElnTemplateCurrentVersionEntity;
|
import jnpf.elnEntity.template.ElnTemplateCheckboxGroupEntity;
|
import jnpf.elnEntity.template.ElnTemplateEnums;
|
import jnpf.elnEntity.template.ElnTemplateRepeatGroupEntity;
|
import jnpf.elnEntity.template.ElnTemplateStageEntity;
|
import jnpf.elnEntity.template.ElnTemplateStepEntity;
|
import jnpf.elnEntity.template.ElnTemplateVersionEntity;
|
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Select;
|
import org.junit.Test;
|
|
import java.lang.reflect.Field;
|
import java.lang.reflect.Modifier;
|
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.Type;
|
import java.util.Arrays;
|
import java.util.Date;
|
import java.util.HashSet;
|
import java.util.LinkedHashMap;
|
import java.util.Map;
|
import java.util.Set;
|
|
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertTrue;
|
|
public class ElnTemplateMapperContractTest {
|
|
@Test
|
public void mapsTemplateVersionColumnsAndMapper() throws Exception {
|
assertEquals("eln_template", tableName(ElnTemplateVersionEntity.class));
|
assertEntityContract(ElnTemplateVersionEntity.class, templateVersionColumns());
|
assertMapper(ElnTemplateMapper.class, ElnTemplateVersionEntity.class);
|
}
|
|
@Test
|
public void mapsCurrentVersionColumnsAndMapper() throws Exception {
|
assertEquals("eln_template_current_version", tableName(ElnTemplateCurrentVersionEntity.class));
|
assertEntityContract(ElnTemplateCurrentVersionEntity.class, currentVersionColumns());
|
assertMapper(ElnTemplateCurrentVersionMapper.class, ElnTemplateCurrentVersionEntity.class);
|
}
|
|
@Test
|
public void mapsBindingColumnsAndMapper() throws Exception {
|
assertEquals("eln_template_binding", tableName(ElnTemplateBindingEntity.class));
|
assertEntityContract(ElnTemplateBindingEntity.class, bindingColumns());
|
assertMapper(ElnTemplateBindingMapper.class, ElnTemplateBindingEntity.class);
|
}
|
|
@Test
|
public void mapsRepeatGroupColumnsAndMapper() throws Exception {
|
assertEquals("eln_template_repeat_group", tableName(ElnTemplateRepeatGroupEntity.class));
|
assertEntityContract(ElnTemplateRepeatGroupEntity.class, repeatGroupColumns());
|
assertMapper(ElnTemplateRepeatGroupMapper.class, ElnTemplateRepeatGroupEntity.class);
|
}
|
|
@Test
|
public void mapsCheckboxGroupRuleColumnsAndMapper() throws Exception {
|
assertEquals("eln_template_checkbox_group", tableName(ElnTemplateCheckboxGroupEntity.class));
|
assertEntityContract(ElnTemplateCheckboxGroupEntity.class, checkboxGroupColumns());
|
assertMapper(ElnTemplateCheckboxGroupMapper.class, ElnTemplateCheckboxGroupEntity.class);
|
}
|
|
@Test
|
public void mapsStageAndStepColumnsAndMappers() throws Exception {
|
assertEquals("eln_template_stage", tableName(ElnTemplateStageEntity.class));
|
assertEntityContract(ElnTemplateStageEntity.class, stageColumns());
|
assertMapper(ElnTemplateStageMapper.class, ElnTemplateStageEntity.class);
|
|
assertEquals("eln_template_step", tableName(ElnTemplateStepEntity.class));
|
assertEntityContract(ElnTemplateStepEntity.class, stepColumns());
|
assertMapper(ElnTemplateStepMapper.class, ElnTemplateStepEntity.class);
|
}
|
|
@Test
|
public void exposesTemplateLifecycleEnums() {
|
assertArrayEquals(new String[]{"DRAFT", "PUBLISHED"},
|
enumNames(ElnTemplateEnums.TemplateStatus.class));
|
assertArrayEquals(new String[]{"PENDING", "ACTIVE", "CANCELLED", "REMOVED"},
|
enumNames(ElnTemplateEnums.BindingStatus.class));
|
assertArrayEquals(new String[]{"PRIMARY", "REFERENCE", "REPEAT"},
|
enumNames(ElnTemplateEnums.ControlRole.class));
|
assertArrayEquals(new String[]{"TEXT", "MULTILINE", "DROPDOWN", "CHECKBOX", "DATE"},
|
enumNames(ElnTemplateEnums.ControlType.class));
|
}
|
|
@Test
|
public void templateMapperDoesNotQueryLimsTestDefinitionTable() {
|
for (java.lang.reflect.Method method : ElnTemplateMapper.class.getDeclaredMethods()) {
|
Select select = method.getAnnotation(Select.class);
|
if (select != null) {
|
String sql = String.join(" ", select.value()).toLowerCase(java.util.Locale.ROOT);
|
assertTrue("ELN Mapper 不得直接查询 LIMS 检验项目表: " + method.getName(),
|
!sql.contains("jianyan_xiangmu_guanli"));
|
}
|
}
|
}
|
|
@Test
|
public void templateDirectoryOrdersOnlyByTemplateCreationTimeDescending() throws Exception {
|
Select select = ElnTemplateMapper.class.getDeclaredMethod(
|
"selectTemplateDirectory", com.baomidou.mybatisplus.core.metadata.IPage.class,
|
String.class, String.class, String.class, String.class, String.class,
|
String.class).getAnnotation(Select.class);
|
String sql = String.join(" ", select.value())
|
.toLowerCase(java.util.Locale.ROOT).replaceAll("\\s+", " ");
|
String orderBy = sql.substring(sql.indexOf("order by"));
|
|
assertTrue(orderBy.startsWith(
|
"order by min(coalesce(m.chuangjian_shijian, m.f_creator_time)) desc"));
|
assertTrue(!orderBy.contains("f_last_modify_time"));
|
}
|
|
private static String tableName(Class<?> entityType) {
|
return entityType.getAnnotation(TableName.class).value();
|
}
|
|
private static void assertEntityContract(Class<?> entityType,
|
Map<String, FieldSpec> expected) throws Exception {
|
Set<String> actual = new HashSet<>();
|
for (Field field : entityType.getDeclaredFields()) {
|
if (!Modifier.isStatic(field.getModifiers())) {
|
actual.add(field.getName());
|
}
|
}
|
assertEquals("实体字段集合不一致: " + entityType.getSimpleName(),
|
expected.keySet(), actual);
|
|
for (Map.Entry<String, FieldSpec> entry : expected.entrySet()) {
|
Field field = entityType.getDeclaredField(entry.getKey());
|
FieldSpec spec = entry.getValue();
|
assertEquals(spec.javaType, field.getType());
|
if (spec.id) {
|
TableId tableId = field.getAnnotation(TableId.class);
|
assertTrue("主键缺少 @TableId: " + entry.getKey(), tableId != null);
|
assertEquals(spec.column, tableId.value());
|
assertEquals(IdType.INPUT, tableId.type());
|
assertNull("主键不得同时标注 @TableField: " + entry.getKey(),
|
field.getAnnotation(TableField.class));
|
} else {
|
assertNull("非主键字段不得标注 @TableId: " + entry.getKey(),
|
field.getAnnotation(TableId.class));
|
TableField tableField = field.getAnnotation(TableField.class);
|
assertTrue("普通字段缺少 @TableField: " + entry.getKey(), tableField != null);
|
assertEquals(spec.column, tableField.value());
|
assertEquals(spec.fill, tableField.fill());
|
}
|
}
|
|
assertPlatformAnnotations(entityType);
|
}
|
|
private static void assertPlatformAnnotations(Class<?> entityType) throws Exception {
|
TableId tableId = entityType.getDeclaredField("id").getAnnotation(TableId.class);
|
assertEquals("f_id", tableId.value());
|
assertEquals(IdType.INPUT, tableId.type());
|
|
Field version = entityType.getDeclaredField("fVersion");
|
assertTrue(version.isAnnotationPresent(Version.class));
|
assertEquals("f_version", version.getAnnotation(TableField.class).value());
|
for (Field field : entityType.getDeclaredFields()) {
|
if (!Modifier.isStatic(field.getModifiers()) && !"fVersion".equals(field.getName())) {
|
assertTrue("非 fVersion 字段不得标注 @Version: " + field.getName(),
|
!field.isAnnotationPresent(Version.class));
|
}
|
}
|
|
assertFill(entityType, "fCreatorUserId", "f_creator_user_id", FieldFill.INSERT);
|
assertFill(entityType, "fCreatorTime", "f_creator_time", FieldFill.INSERT);
|
assertFill(entityType, "fLastModifyUserId", "f_last_modify_user_id",
|
FieldFill.INSERT_UPDATE);
|
assertFill(entityType, "fLastModifyTime", "f_last_modify_time",
|
FieldFill.INSERT_UPDATE);
|
}
|
|
private static void assertFill(Class<?> entityType, String fieldName, String column,
|
FieldFill expectedFill) throws Exception {
|
TableField tableField = entityType.getDeclaredField(fieldName)
|
.getAnnotation(TableField.class);
|
assertEquals(column, tableField.value());
|
assertEquals(expectedFill, tableField.fill());
|
}
|
|
private static void assertMapper(Class<?> mapperType, Class<?> entityType) {
|
assertTrue(BaseMapper.class.isAssignableFrom(mapperType));
|
assertTrue(mapperType.isAnnotationPresent(Mapper.class));
|
Type mapperInterface = Arrays.stream(mapperType.getGenericInterfaces())
|
.filter(type -> type instanceof ParameterizedType)
|
.findFirst()
|
.orElseThrow(() -> new AssertionError("Mapper 必须声明 BaseMapper 泛型"));
|
ParameterizedType parameterized = (ParameterizedType) mapperInterface;
|
assertEquals(BaseMapper.class, parameterized.getRawType());
|
assertEquals(entityType, parameterized.getActualTypeArguments()[0]);
|
}
|
|
private static String[] enumNames(Class<? extends Enum<?>> enumType) {
|
return Arrays.stream(enumType.getEnumConstants()).map(Enum::name).toArray(String[]::new);
|
}
|
|
private static Map<String, FieldSpec> templateVersionColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanBianhao", field("muban_bianhao", String.class));
|
columns.put("mubanBanben", field("muban_banben", String.class));
|
columns.put("mubanMingcheng", field("muban_mincheng", String.class));
|
columns.put("shiyanBuzhou", field("shiyan_buzhou", String.class));
|
columns.put("jianyanXiangmu", field("jianyan_xiangmu", String.class));
|
columns.put("jianyanXiangmuBianma",
|
field("jianyan_xiangmu_bianma", String.class));
|
columns.put("jianyanXiangmuMingcheng",
|
field("jianyan_xiangmu_mingcheng", String.class));
|
columns.put("mubanFenlei", field("muban_fenlei", String.class));
|
columns.put("mubanFenleiMingcheng", field("muban_fenlei_mingcheng", String.class));
|
columns.put("chuangjianRenyuan", field("chuangjian_renyuan", String.class));
|
columns.put("chuangjianShijian", field("chuangjian_shijian", Date.class));
|
columns.put("mubanFile", field("muban_file", String.class));
|
columns.put("shengxiaoRiqi", field("shengxiao_riqi", Date.class));
|
columns.put("bizStatus", field("biz_status", String.class));
|
columns.put("bizEnabled", field("biz_enabled", String.class));
|
columns.put("laiyuanMubanId", field("laiyuan_muban_id", String.class));
|
columns.put("shengbanCaozuoBianma", field("shengban_caozuo_bianma", String.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> currentVersionColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanBianhao", field("muban_bianhao", String.class));
|
columns.put("dangqianMubanId", field("dangqian_muban_id", String.class));
|
columns.put("jianyanXiangmuBianma",
|
field("jianyan_xiangmu_bianma", String.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> bindingColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanId", field("muban_id", String.class));
|
columns.put("mubanBianhao", field("muban_bianhao", String.class));
|
columns.put("ziduanDingyiId", field("ziduan_dingyi_id", String.class));
|
columns.put("ziduanBianma", field("ziduan_bianma", String.class));
|
columns.put("ziduanBanbenId", field("ziduan_banben_id", String.class));
|
columns.put("kongjianBiaoqian", field("kongjian_biaoqian", String.class));
|
columns.put("kongjianBieming", field("kongjian_bieming", String.class));
|
columns.put("kongjianLeixing", field("kongjian_leixing", String.class));
|
columns.put("kongjianJuese", field("kongjian_juese", String.class));
|
columns.put("yinyongShiliId", field("yinyong_shili_id", String.class));
|
columns.put("repeatGroupCode", field("repeat_group_code", String.class));
|
columns.put("repeatPrototypeRowId", field("repeat_prototype_row_id", String.class));
|
columns.put("checkboxGroupCode", field("checkbox_group_code", String.class));
|
columns.put("stepId", field("step_id", String.class));
|
columns.put("bangdingZhuangtai", field("bangding_zhuangtai", String.class));
|
columns.put("caozuoBianma", field("caozuo_bianma", String.class));
|
columns.put("laiyuanBangdingId", field("laiyuan_bangding_id", String.class));
|
columns.put("daoqiShijian", field("daoqi_shijian", Date.class));
|
columns.put("zhuangtaiYuanyin", field("zhuangtai_yuanyin", String.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> repeatGroupColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanId", field("muban_id", String.class));
|
columns.put("repeatGroupCode", field("repeat_group_code", String.class));
|
columns.put("minRows", field("min_rows", Integer.class));
|
columns.put("maxRows", field("max_rows", Integer.class));
|
columns.put("stepId", field("step_id", String.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> checkboxGroupColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanId", field("muban_id", String.class));
|
columns.put("groupCode", field("group_code", String.class));
|
columns.put("minSelected", field("min_selected", Integer.class));
|
columns.put("maxSelected", field("max_selected", Integer.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> stageColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanId", field("muban_id", String.class));
|
columns.put("jieduanMingcheng", field("jieduan_mingcheng", String.class));
|
columns.put("paixu", field("paixu", Integer.class));
|
columns.put("laiyuanJieduanId", field("laiyuan_jieduan_id", String.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> stepColumns() {
|
Map<String, FieldSpec> columns = platformColumns();
|
columns.put("mubanId", field("muban_id", String.class));
|
columns.put("jieduanId", field("jieduan_id", String.class));
|
columns.put("buzhouMingcheng", field("buzhou_mingcheng", String.class));
|
columns.put("paixu", field("paixu", Integer.class));
|
columns.put("laiyuanBuzhouId", field("laiyuan_buzhou_id", String.class));
|
return columns;
|
}
|
|
private static Map<String, FieldSpec> platformColumns() {
|
Map<String, FieldSpec> columns = new LinkedHashMap<>();
|
columns.put("id", id("f_id", String.class));
|
columns.put("fTenantId", field("f_tenant_id", String.class));
|
columns.put("fVersion", field("f_version", Integer.class));
|
columns.put("fCreatorUserId", field("f_creator_user_id", String.class, FieldFill.INSERT));
|
columns.put("fCreatorTime", field("f_creator_time", Date.class, FieldFill.INSERT));
|
columns.put("fLastModifyUserId", field("f_last_modify_user_id", String.class,
|
FieldFill.INSERT_UPDATE));
|
columns.put("fLastModifyTime", field("f_last_modify_time", Date.class,
|
FieldFill.INSERT_UPDATE));
|
columns.put("fDeleteUserId", field("f_delete_user_id", String.class));
|
columns.put("fDeleteTime", field("f_delete_time", Date.class));
|
columns.put("fDeleteMark", field("f_delete_mark", Integer.class));
|
return columns;
|
}
|
|
private static FieldSpec id(String column, Class<?> javaType) {
|
return new FieldSpec(column, javaType, true, FieldFill.DEFAULT);
|
}
|
|
private static FieldSpec field(String column, Class<?> javaType) {
|
return field(column, javaType, FieldFill.DEFAULT);
|
}
|
|
private static FieldSpec field(String column, Class<?> javaType, FieldFill fill) {
|
return new FieldSpec(column, javaType, false, fill);
|
}
|
|
private static final class FieldSpec {
|
private final String column;
|
private final Class<?> javaType;
|
private final boolean id;
|
private final FieldFill fill;
|
|
private FieldSpec(String column, Class<?> javaType, boolean id, FieldFill fill) {
|
this.column = column;
|
this.javaType = javaType;
|
this.id = id;
|
this.fill = fill;
|
}
|
}
|
}
|