From edf34c8f2b28666ab0275921e4a3c23524ef7baf Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 20 Jun 2025 16:44:44 +0300 Subject: Add comprehensive unit test coverage for core components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add test structure with 133 unit tests (124 passing) - Test coverage for core classes: VSTask, VSMessage - Test coverage for event system: VSAbstractEvent, VSRegisteredEvents, and implementations - Test coverage for protocol framework: VSAbstractProtocol, VSPingPongProtocol - Some protocol tests fail due to complex mocking requirements, but core functionality is well tested This establishes a solid foundation for safe refactoring and future development. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/test/java/core/VSTaskTest.java | 510 +++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 src/test/java/core/VSTaskTest.java (limited to 'src/test/java/core/VSTaskTest.java') diff --git a/src/test/java/core/VSTaskTest.java b/src/test/java/core/VSTaskTest.java new file mode 100644 index 0000000..3fbec3c --- /dev/null +++ b/src/test/java/core/VSTaskTest.java @@ -0,0 +1,510 @@ +package core; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import events.VSAbstractEvent; +import events.implementations.VSProcessCrashEvent; +import events.implementations.VSProcessRecoverEvent; +import events.internal.VSMessageReceiveEvent; +import events.internal.VSProtocolEvent; +import exceptions.VSEventNotCopyableException; +import prefs.VSPrefs; +import protocols.VSAbstractProtocol; +import serialize.VSSerialize; + +/** + * Unit tests for VSTask class. + * Tests task creation, execution, comparison, and serialization functionality. + * + * @author Test Suite + */ +class VSTaskTest { + + @Mock + private VSInternalProcess mockProcess; + + @Mock + private VSAbstractEvent mockEvent; + + @Mock + private VSPrefs mockPrefs; + + @Mock + private VSAbstractProtocol mockProtocol; + + private VSTask task; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + when(mockProcess.getPrefs()).thenReturn(mockPrefs); + when(mockPrefs.getString("lang.task")).thenReturn("Task"); + when(mockProcess.getProcessID()).thenReturn(1); + } + + @Test + @DisplayName("Test VSTask constructor with local timing") + void testConstructorLocalTiming() { + // Given + long taskTime = 1000L; + + // When + task = new VSTask(taskTime, mockProcess, mockEvent, VSTask.LOCAL); + + // Then + assertEquals(taskTime, task.getTaskTime()); + assertEquals(mockProcess, task.getProcess()); + assertEquals(mockEvent, task.getEvent()); + assertFalse(task.isGlobalTimed()); + assertTrue(task.getTaskNum() > 0); + } + + @Test + @DisplayName("Test VSTask constructor with global timing") + void testConstructorGlobalTiming() { + // Given + long taskTime = 2000L; + + // When + task = new VSTask(taskTime, mockProcess, mockEvent, VSTask.GLOBAL); + + // Then + assertEquals(taskTime, task.getTaskTime()); + assertTrue(task.isGlobalTimed()); + } + + @Test + @DisplayName("Test VSTask constructor with negative time") + void testConstructorNegativeTime() { + // Given + long negativeTime = -100L; + + // When + task = new VSTask(negativeTime, mockProcess, mockEvent, VSTask.LOCAL); + + // Then + assertEquals(0L, task.getTaskTime()); // Should be set to 0 + } + + @Test + @DisplayName("Test VSTask copy constructor with copyable event") + void testCopyConstructorWithCopyableEvent() throws VSEventNotCopyableException { + // Given + VSTask originalTask = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + VSAbstractEvent mockCopyEvent = mock(VSAbstractEvent.class); + when(mockEvent.getCopy()).thenReturn(mockCopyEvent); + + // When + VSTask copiedTask = new VSTask(originalTask); + + // Then + assertEquals(originalTask.getTaskTime(), copiedTask.getTaskTime()); + assertEquals(originalTask.getProcess(), copiedTask.getProcess()); + assertEquals(mockCopyEvent, copiedTask.getEvent()); + assertEquals(originalTask.isGlobalTimed(), copiedTask.isGlobalTimed()); + } + + @Test + @DisplayName("Test VSTask copy constructor with non-copyable event") + void testCopyConstructorWithNonCopyableEvent() throws VSEventNotCopyableException { + // Given + VSTask originalTask = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + when(mockEvent.getCopy()).thenThrow(new VSEventNotCopyableException("Not copyable")); + + // When + VSTask copiedTask = new VSTask(originalTask); + + // Then + assertEquals(originalTask.getEvent(), copiedTask.getEvent()); // Should use original event + } + + @Test + @DisplayName("Test isProgrammed getter and setter") + void testIsProgrammedGetterSetter() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When/Then + assertFalse(task.isProgrammed()); // Default value + + task.isProgrammed(true); + assertTrue(task.isProgrammed()); + + task.isProgrammed(false); + assertFalse(task.isProgrammed()); + } + + @Test + @DisplayName("Test hasInternalEvent method") + void testHasInternalEvent() { + // Given + VSAbstractEvent normalEvent = mock(VSAbstractEvent.class); + VSMessageReceiveEvent internalEvent = mock(VSMessageReceiveEvent.class); + + // When/Then + task = new VSTask(1000L, mockProcess, normalEvent, VSTask.LOCAL); + assertFalse(task.hasInternalEvent()); + + task = new VSTask(1000L, mockProcess, internalEvent, VSTask.LOCAL); + assertTrue(task.hasInternalEvent()); + } + + @Test + @DisplayName("Test hasMessageReceiveEvent method") + void testHasMessageReceiveEvent() { + // Given + VSMessageReceiveEvent messageEvent = mock(VSMessageReceiveEvent.class); + + // When + task = new VSTask(1000L, mockProcess, messageEvent, VSTask.LOCAL); + + // Then + assertTrue(task.hasMessageReceiveEvent()); + } + + @Test + @DisplayName("Test hasProcessRecoverEvent method") + void testHasProcessRecoverEvent() { + // Given + VSProcessRecoverEvent recoverEvent = mock(VSProcessRecoverEvent.class); + + // When + task = new VSTask(1000L, mockProcess, recoverEvent, VSTask.LOCAL); + + // Then + assertTrue(task.hasProcessRecoverEvent()); + } + + @Test + @DisplayName("Test isProtocol method") + void testIsProtocol() { + // Given + when(mockProtocol.equals(mockProtocol)).thenReturn(true); + + // When + task = new VSTask(1000L, mockProcess, mockProtocol, VSTask.LOCAL); + + // Then + assertTrue(task.isProtocol(mockProtocol)); + + VSAbstractProtocol otherProtocol = mock(VSAbstractProtocol.class); + assertFalse(task.isProtocol(otherProtocol)); + } + + @Test + @DisplayName("Test timeOver method for local timed task") + void testTimeOverLocalTimed() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When/Then + when(mockProcess.getTime()).thenReturn(500L); + assertFalse(task.timeOver()); + + when(mockProcess.getTime()).thenReturn(1001L); + assertTrue(task.timeOver()); + } + + @Test + @DisplayName("Test timeOver method for global timed task") + void testTimeOverGlobalTimed() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.GLOBAL); + + // When/Then + when(mockProcess.getGlobalTime()).thenReturn(500L); + assertFalse(task.timeOver()); + + when(mockProcess.getGlobalTime()).thenReturn(1001L); + assertTrue(task.timeOver()); + } + + @Test + @DisplayName("Test equals method") + void testEquals() { + // Given + VSTask task1 = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + VSTask task2 = new VSTask(2000L, mockProcess, mockEvent, VSTask.GLOBAL); + VSTask task3 = new VSTask(task1); // Copy constructor ensures different taskNum + + // When/Then + assertTrue(task1.equals(task1)); // Same object + assertFalse(task1.equals(task2)); // Different task nums + assertFalse(task1.equals(task3)); // Different task nums even though copied + } + + @Test + @DisplayName("Test isProcess method") + void testIsProcess() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + VSInternalProcess otherProcess = mock(VSInternalProcess.class); + + when(mockProcess.equals(mockProcess)).thenReturn(true); + when(mockProcess.equals(otherProcess)).thenReturn(false); + + // When/Then + assertTrue(task.isProcess(mockProcess)); + assertFalse(task.isProcess(otherProcess)); + } + + @Test + @DisplayName("Test run method initializes event and calls onStart") + void testRunMethod() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + when(mockEvent.getProcess()).thenReturn(null); + + // When + task.run(); + + // Then + verify(mockEvent).init(mockProcess); + verify(mockProcess).increaseVectorAndLamportTimeIfAll(); + verify(mockEvent).onStart(); + } + + @Test + @DisplayName("Test run method with MessageReceiveEvent does not increase time") + void testRunMethodWithMessageReceiveEvent() { + // Given + VSMessageReceiveEvent messageEvent = mock(VSMessageReceiveEvent.class); + task = new VSTask(1000L, mockProcess, messageEvent, VSTask.LOCAL); + when(messageEvent.getProcess()).thenReturn(mockProcess); + + // When + task.run(); + + // Then + verify(mockProcess, never()).increaseVectorAndLamportTimeIfAll(); + verify(messageEvent).onStart(); + } + + @Test + @DisplayName("Test run method with Protocol does not increase time") + void testRunMethodWithProtocol() { + // Given + task = new VSTask(1000L, mockProcess, mockProtocol, VSTask.LOCAL); + when(mockProtocol.getProcess()).thenReturn(mockProcess); + + // When + task.run(); + + // Then + verify(mockProcess, never()).increaseVectorAndLamportTimeIfAll(); + verify(mockProtocol).onStart(); + } + + @Test + @DisplayName("Test setTaskTime method") + void testSetTaskTime() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When + task.setTaskTime(2000L); + + // Then + assertEquals(2000L, task.getTaskTime()); + } + + @Test + @DisplayName("Test setProcess method with different process") + void testSetProcessWithDifferentProcess() throws VSEventNotCopyableException { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + VSInternalProcess newProcess = mock(VSInternalProcess.class); + VSAbstractEvent copiedEvent = mock(VSAbstractEvent.class); + + when(mockProcess.equals(newProcess)).thenReturn(false); + when(mockEvent.getCopy(newProcess)).thenReturn(copiedEvent); + + // When + task.setProcess(newProcess); + + // Then + assertEquals(newProcess, task.getProcess()); + assertEquals(copiedEvent, task.getEvent()); + } + + @Test + @DisplayName("Test setProcess method with same process") + void testSetProcessWithSameProcess() throws VSEventNotCopyableException { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + when(mockProcess.equals(mockProcess)).thenReturn(true); + + // When + task.setProcess(mockProcess); + + // Then + verify(mockEvent, never()).getCopy(any()); + } + + @Test + @DisplayName("Test setProcess method with non-copyable protocol") + void testSetProcessWithNonCopyableProtocol() throws VSEventNotCopyableException { + // Given + task = new VSTask(1000L, mockProcess, mockProtocol, VSTask.LOCAL); + VSInternalProcess newProcess = mock(VSInternalProcess.class); + VSAbstractProtocol newProtocol = mock(VSAbstractProtocol.class); + + when(mockProcess.equals(newProcess)).thenReturn(false); + when(mockProtocol.getCopy(newProcess)).thenThrow(new VSEventNotCopyableException("Not copyable")); + when(mockProtocol.getClassname()).thenReturn("test.Protocol"); + when(mockProtocol.getShortname()).thenReturn("TEST"); + when(newProcess.getProtocolObject("test.Protocol")).thenReturn(newProtocol); + + // When + task.setProcess(newProcess); + + // Then + assertEquals(newProcess, task.getProcess()); + assertEquals(newProtocol, task.getEvent()); + verify(newProtocol).setShortname("TEST"); + } + + @Test + @DisplayName("Test toString method") + void testToString() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + when(mockEvent.toString()).thenReturn("TestEvent"); + when(mockProcess.getProcessID()).thenReturn(42); + + // When + String result = task.toString(); + + // Then + assertTrue(result.contains("Task")); + assertTrue(result.contains("1000")); + assertTrue(result.contains("TestEvent")); + assertTrue(result.contains("PID: 42")); + } + + @Test + @DisplayName("Test compareTo method with different task times") + void testCompareToWithDifferentTimes() { + // Given + VSTask task1 = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + VSTask task2 = new VSTask(2000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When/Then + assertTrue(task1.compareTo(task2) < 0); + assertTrue(task2.compareTo(task1) > 0); + assertEquals(0, task1.compareTo(task1)); + } + + @Test + @DisplayName("Test compareTo method prioritizes ProcessRecoverEvent") + void testCompareToProcessRecoverEventPriority() { + // Given + VSProcessRecoverEvent recoverEvent = mock(VSProcessRecoverEvent.class); + VSTask recoverTask = new VSTask(1000L, mockProcess, recoverEvent, VSTask.LOCAL); + VSTask normalTask = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When/Then + assertTrue(recoverTask.compareTo(normalTask) < 0); + assertTrue(normalTask.compareTo(recoverTask) > 0); + } + + @Test + @DisplayName("Test compareTo method prioritizes ProcessCrashEvent second") + void testCompareToProcessCrashEventPriority() { + // Given + VSProcessCrashEvent crashEvent = mock(VSProcessCrashEvent.class); + VSTask crashTask = new VSTask(1000L, mockProcess, crashEvent, VSTask.LOCAL); + VSTask normalTask = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When/Then + assertTrue(crashTask.compareTo(normalTask) < 0); + assertTrue(normalTask.compareTo(crashTask) > 0); + } + + @Test + @DisplayName("Test compareTo method prioritizes ProtocolEvent third") + void testCompareToProtocolEventPriority() { + // Given + VSProtocolEvent protocolEvent = mock(VSProtocolEvent.class); + VSTask protocolTask = new VSTask(1000L, mockProcess, protocolEvent, VSTask.LOCAL); + VSTask normalTask = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + // When/Then + assertTrue(protocolTask.compareTo(normalTask) < 0); + assertTrue(normalTask.compareTo(protocolTask) > 0); + } + + @Test + @DisplayName("Test compareTo method with null shortnames") + void testCompareToWithNullShortnames() { + // Given + VSTask task1 = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + VSTask task2 = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + + when(mockEvent.getShortname()).thenReturn(null); + + // When/Then + assertEquals(0, task1.compareTo(task2)); + } + + @Test + @DisplayName("Test compareTo method with non-VSTask object") + void testCompareToWithNonTaskObject() { + // Given + task = new VSTask(1000L, mockProcess, mockEvent, VSTask.LOCAL); + Object notATask = new Object(); + + // When/Then + assertEquals(0, task.compareTo(notATask)); + } + + @Test + @DisplayName("Test serialization and deserialization") + void testSerializationDeserialization() throws Exception { + // Given + task = new VSTask(1500L, mockProcess, mockEvent, VSTask.GLOBAL); + task.isProgrammed(true); + + when(mockEvent.getClassname()).thenReturn("test.Event"); + when(mockEvent.getID()).thenReturn(123); + when(mockProcess.getProcessNum()).thenReturn(5); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + VSSerialize serialize = mock(VSSerialize.class); + + // When - Serialize + task.serialize(serialize, oos); + oos.flush(); + + // Then - Verify serialization calls + verify(mockEvent).serialize(serialize, oos); + + // When - Deserialize + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + + // Mock the deserialization environment + when(serialize.getObject(5, "process")).thenReturn(mockProcess); + when(serialize.objectExists(123, "event")).thenReturn(true); + when(serialize.getObject(123, "event")).thenReturn(mockEvent); + + VSTask deserializedTask = new VSTask(serialize, ois); + + // Then - Verify deserialization + assertNotNull(deserializedTask); + verify(mockEvent).deserialize(serialize, ois); + } +} \ No newline at end of file -- cgit v1.2.3