package jnpf.base.util; import jnpf.base.model.uploadedit.UploadEditDraft; import jnpf.exception.DataException; import jnpf.util.JsonUtil; import jnpf.util.TicketUtil; import org.junit.Test; import java.util.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class UploadTemplateSourceTest { Map file(String id, String template) { Map file = new LinkedHashMap<>(); file.put("fileId", id); file.put("name", "same.docx"); if (template != null) file.put(UploadTemplateSource.FIELD, template); return file; } @Test public void editingKeepsSourceDeletingReuploadingClearsAndDiscardRestores() { UploadEditDraft draft = new UploadEditDraft(); draft.setRevision(0L); draft.setBaselineJson(JsonUtil.getObjectToString(List.of(file("A", "templateA")))); draft.setCurrentJson(draft.getBaselineJson()); UploadEditStateMachine.begin(draft, 0L, "A"); String lease = draft.getLeaseId(); assertTrue(UploadEditStateMachine.save(draft, lease, "save1", file("edited", "forged"))); assertEquals("templateA", UploadEditStateMachine.files(draft.getCurrentJson()).get(0).get(UploadTemplateSource.FIELD)); UploadEditStateMachine.replace(draft, draft.getRevision(), List.of()); assertFalse(UploadEditStateMachine.save(draft, lease, "late", file("late", "templateA"))); var upload = file("new", "forged"); UploadTemplateSource.normalize(List.of(upload), List.of(file("A", "templateA")), "tenant", "owner"); assertFalse(upload.containsKey(UploadTemplateSource.FIELD)); UploadEditStateMachine.replace(draft, draft.getRevision(), List.of(upload)); UploadEditStateMachine.discard(draft, draft.getRevision()); assertEquals("templateA", UploadEditStateMachine.files(draft.getCurrentJson()).get(0).get(UploadTemplateSource.FIELD)); } @Test public void newVerifiedReceiptOverridesSameFileIdAndRejectsForgedReceipt() { var submitted = file("A", "forged"); submitted.put("uploadReceipt", "new"); Map proof = file("A", "templateB"); proof.put("purpose", "upload-edit-source"); proof.put("tenantId", "tenant"); proof.put("ownerId", "owner"); try (var tickets = mockStatic(TicketUtil.class)) { tickets.when(() -> TicketUtil.parseTicket("new")).thenReturn(JsonUtil.getObjectToString(proof)); UploadTemplateSource.normalize(List.of(submitted), List.of(file("A", "templateA")), "tenant", "owner"); assertEquals("templateB", submitted.get(UploadTemplateSource.FIELD)); try { UploadTemplateSource.normalize(List.of(submitted), List.of(), "other", "owner"); fail("tenant mismatch must fail"); } catch (DataException expected) { } } } @Test public void serverTimeIsPreservedButClientTimeIsNotTrusted() { var trusted = file("A", "templateA"); trusted.put("contentSavedAt", 100L); var submitted = file("A", "forged"); submitted.put("contentSavedAt", 999L); UploadTemplateSource.normalize(List.of(submitted), List.of(trusted), "tenant", "owner"); assertEquals(100L, submitted.get("contentSavedAt")); var ordinary = file("B", "forged"); ordinary.put("contentSavedAt", 999L); UploadTemplateSource.normalize(List.of(ordinary), List.of(trusted), "tenant", "owner"); assertFalse(ordinary.containsKey("contentSavedAt")); assertFalse(ordinary.containsKey(UploadTemplateSource.FIELD)); } @Test public void savedCopyKeepsTemplateButUsesNewServerTimeAndMetadataToken() { var original = file("A", "templateA"); original.put("contentSavedAt", 100L); UploadEditDraft draft = new UploadEditDraft(); draft.setRevision(0L); draft.setBaselineJson(JsonUtil.getObjectToString(List.of(original))); draft.setCurrentJson(draft.getBaselineJson()); UploadEditStateMachine.begin(draft, 0L, "A"); var saved = file("B", "forged"); saved.put("contentSavedAt", 200L); assertTrue(UploadEditStateMachine.save(draft, draft.getLeaseId(), "saved", saved)); var actual = UploadEditStateMachine.files(draft.getCurrentJson()).get(0); assertEquals("templateA", actual.get(UploadTemplateSource.FIELD)); assertEquals(200L, ((Number) actual.get("contentSavedAt")).longValue()); var otherTemplate = file("A", "templateB"); otherTemplate.put("contentSavedAt", 100L); assertEquals(UploadEditStateMachine.contentToken(List.of(original)), UploadEditStateMachine.contentToken(List.of(otherTemplate))); assertNotEquals(UploadEditStateMachine.metadataToken(List.of(original)), UploadEditStateMachine.metadataToken(List.of(otherTemplate))); } }