package jnpf.flowable.service; import jnpf.flowable.mapper.DmsLifecycleNativeFormMapper; import org.junit.Test; import java.util.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class DmsRevisionAttachmentSubmissionTest { private final DmsLifecycleNativeFormMapper mapper=mock(DmsLifecycleNativeFormMapper.class); private final DmsLifecycleSubmissionGuard guard=new DmsLifecycleSubmissionGuard(mapper,null,null,false); private jnpf.file.FileContentApi api; @org.junit.Before public void configureContentApi() throws Exception { api = mock(jnpf.file.FileContentApi.class); var response = new jnpf.base.ActionResult(); response.setCode(200); response.setData(false); when(api.sameContent(anyString(), any())).thenReturn(response); var field = DmsLifecycleSubmissionGuard.class.getDeclaredField("fileContentApi"); field.setAccessible(true); field.set(guard, api); } private static final String ORIGINAL="[{\"fileId\":\"a\",\"url\":\"/a\"}]"; private static T assertThrows(Class type,Runnable action) { try { action.run(); } catch(Throwable failure) { if(type.isInstance(failure)) return type.cast(failure); throw new AssertionError(failure); } throw new AssertionError("Expected "+type.getName()); } private Map row(Object attachment) { Map row=new HashMap<>(); row.put("biangeng_fangshi","wubianhua");row.put("jilu_wenjian_id","record"); row.put("yuan_wenjian_banben_id","version");row.put("jilu_wenjian",attachment); row.put("shifou_shoukong","yes");row.put("fujian_mingcheng","new name"); return row; } @Test public void metadataChangesAndJsonPropertyOrderAreAllowed() { when(mapper.revisionAttachment("tenant","record","version")).thenReturn(ORIGINAL); guard.validateRevisionAttachments("tenant",Map.of(),List.of( row("[{\"url\":\"/a\",\"fileId\":\"a\"}]"))); guard.validateRevisionAttachments("tenant",Map.of(),List.of( row(List.of(Map.of("fileId","a","url","/a"))))); } @Test public void changedRemovedMissingOrMalformedAttachmentsAreRejected() { when(mapper.revisionAttachment("tenant","record","version")).thenReturn(ORIGINAL); for(Object attachment:Arrays.asList("[{\"fileId\":\"b\",\"url\":\"/b\"}]","[]","",null,"broken",Map.of())) { var failure=assertThrows(IllegalArgumentException.class, ()->guard.validateRevisionAttachments("tenant",Map.of(),List.of(row(attachment)))); assertTrue(failure.getMessage().contains("第1行记录")); assertTrue(failure.getMessage().contains("升级")); } } @Test public void missingAuthoritativeVersionCannotBeAccepted() { assertThrows(IllegalArgumentException.class,()->guard.validateRevisionAttachments("other",Map.of(),List.of(row(ORIGINAL)))); } @Test public void upgradedAttachmentIsNotSubjectToReuseValidation() { var row=row("[{\"fileId\":\"b\"}]");row.put("biangeng_fangshi","shengji"); guard.validateRevisionAttachments("tenant",Map.of("biangeng_fangshi","shengji"),List.of(row)); verifyNoInteractions(mapper); } @Test public void mainSharedAttachmentMustMatchFixedOriginalVersion() { assertThrows(IllegalArgumentException.class, () -> guard.validateRevisionAttachments("tenant",Map.of("biangeng_fangshi","wubianhua", "xiuding_shenqing_zixiang_id","detail","wenjian","[]"),List.of())); verify(mapper).revisionMainAttachment("tenant", "detail"); } @Test public void repeatedImmutableEditComparisonReusesResultButRechecksOriginalAndTenant() { when(mapper.revisionAttachment("tenant", "record", "version")).thenReturn(ORIGINAL); var equal = new jnpf.base.ActionResult(); equal.setCode(200); equal.setData(true); when(api.sameContent(anyString(), any())).thenReturn(equal); String id = "onlyoffice-edit-temp," + "a".repeat(32) + "," + "b".repeat(32) + ",saved.docx"; var row = row(List.of(Map.of("fileId", id, "url", "/saved"))); guard.validateRevisionAttachments("tenant", Map.of(), List.of(row)); guard.validateRevisionAttachments("tenant", Map.of(), List.of(row)); verify(api, times(1)).sameContent(anyString(), any()); verify(mapper, times(2)).revisionAttachment("tenant", "record", "version"); when(mapper.revisionAttachment("tenant", "record", "version")).thenReturn("[{\"fileId\":\"new-original\",\"url\":\"/new\"}]"); guard.validateRevisionAttachments("tenant", Map.of(), List.of(row)); verify(api, times(2)).sameContent(anyString(), any()); assertThrows(IllegalArgumentException.class, () -> guard.validateRevisionAttachments("other", Map.of(), List.of(row))); } @Test public void ordinaryMutableFilesDoNotReuseComparisonResults() { when(mapper.revisionAttachment("tenant", "record", "version")).thenReturn(ORIGINAL); var equal = new jnpf.base.ActionResult(); equal.setCode(200); equal.setData(true); when(api.sameContent(anyString(), any())).thenReturn(equal); var row = row(List.of(Map.of("fileId", "ordinary", "url", "/ordinary"))); guard.validateRevisionAttachments("tenant", Map.of(), List.of(row)); guard.validateRevisionAttachments("tenant", Map.of(), List.of(row)); verify(api, times(2)).sameContent(anyString(), any()); } }