summaryrefslogtreecommitdiff
path: root/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java')
-rw-r--r--src/test/java/core/VSMessageTest.java315
-rw-r--r--src/test/java/core/VSTaskTest.java510
-rw-r--r--src/test/java/events/VSAbstractEventTest.java271
-rw-r--r--src/test/java/events/VSRegisteredEventsTest.java324
-rw-r--r--src/test/java/events/implementations/VSProcessCrashEventTest.java198
-rw-r--r--src/test/java/events/implementations/VSProcessRecoverEventTest.java236
-rw-r--r--src/test/java/protocols/VSAbstractProtocolTest.java368
-rw-r--r--src/test/java/protocols/implementations/VSPingPongProtocolTest.java262
8 files changed, 2484 insertions, 0 deletions
diff --git a/src/test/java/core/VSMessageTest.java b/src/test/java/core/VSMessageTest.java
new file mode 100644
index 0000000..0826244
--- /dev/null
+++ b/src/test/java/core/VSMessageTest.java
@@ -0,0 +1,315 @@
+package core;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+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 core.time.VSVectorTime;
+import events.VSRegisteredEvents;
+import prefs.VSPrefs;
+
+/**
+ * Unit tests for VSMessage class.
+ * Tests message creation, initialization, and various getter/setter functionality.
+ *
+ * @author Test Suite
+ */
+class VSMessageTest {
+
+ @Mock
+ private VSInternalProcess mockSendingProcess;
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ @Mock
+ private VSVectorTime mockVectorTime;
+
+ @Mock
+ private VSVectorTime mockVectorTimeCopy;
+
+ private VSMessage message;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ // Setup common mocks
+ when(mockSendingProcess.getPrefs()).thenReturn(mockPrefs);
+ when(mockSendingProcess.getLamportTime()).thenReturn(42L);
+ when(mockSendingProcess.getVectorTime()).thenReturn(mockVectorTime);
+ when(mockVectorTime.getCopy()).thenReturn(mockVectorTimeCopy);
+
+ when(mockPrefs.getString("lang.protocol")).thenReturn("Protocol");
+
+ message = new VSMessage();
+ }
+
+ @Test
+ @DisplayName("Test VSMessage constructor creates unique message IDs")
+ void testConstructorCreatesUniqueIds() {
+ // Given/When
+ VSMessage message1 = new VSMessage();
+ VSMessage message2 = new VSMessage();
+ VSMessage message3 = new VSMessage();
+
+ // Then
+ assertNotEquals(message1.getMessageID(), message2.getMessageID());
+ assertNotEquals(message2.getMessageID(), message3.getMessageID());
+ assertNotEquals(message1.getMessageID(), message3.getMessageID());
+ assertTrue(message2.getMessageID() > message1.getMessageID());
+ assertTrue(message3.getMessageID() > message2.getMessageID());
+ }
+
+ @Test
+ @DisplayName("Test init method for server message")
+ void testInitServerMessage() {
+ // Given
+ String protocolClassname = "test.protocol.MyProtocol";
+
+ // When
+ message.init(mockSendingProcess, protocolClassname, VSMessage.IS_SERVER_MESSAGE);
+
+ // Then
+ assertEquals(mockSendingProcess, message.getSendingProcess());
+ assertEquals(protocolClassname, message.getProtocolClassname());
+ assertTrue(message.isServerMessage());
+ assertEquals(42L, message.getLamportTime());
+ assertEquals(mockVectorTimeCopy, message.getVectorTime());
+ }
+
+ @Test
+ @DisplayName("Test init method for client message")
+ void testInitClientMessage() {
+ // Given
+ String protocolClassname = "test.protocol.ClientProtocol";
+
+ // When
+ message.init(mockSendingProcess, protocolClassname, VSMessage.IS_CLIENT_MESSAGE);
+
+ // Then
+ assertEquals(mockSendingProcess, message.getSendingProcess());
+ assertEquals(protocolClassname, message.getProtocolClassname());
+ assertFalse(message.isServerMessage());
+ }
+
+ @Test
+ @DisplayName("Test getName method")
+ void testGetName() {
+ // Given
+ String protocolClassname = "test.protocol.MyProtocol";
+ String expectedName = "My Protocol";
+ message.init(mockSendingProcess, protocolClassname, VSMessage.IS_SERVER_MESSAGE);
+
+ // Mock static method behavior
+ try (var mockedStatic = mockStatic(VSRegisteredEvents.class)) {
+ mockedStatic.when(() -> VSRegisteredEvents.getNameByClassname(protocolClassname))
+ .thenReturn(expectedName);
+
+ // When
+ String name = message.getName();
+
+ // Then
+ assertEquals(expectedName, name);
+ }
+ }
+
+ @Test
+ @DisplayName("Test getMessageID returns correct ID")
+ void testGetMessageID() {
+ // Given - message created in setUp
+
+ // When
+ long messageId = message.getMessageID();
+
+ // Then
+ assertTrue(messageId > 0);
+ }
+
+ @Test
+ @DisplayName("Test getSendingProcess returns correct process")
+ void testGetSendingProcess() {
+ // Given
+ message.init(mockSendingProcess, "test.Protocol", VSMessage.IS_SERVER_MESSAGE);
+
+ // When
+ VSAbstractProcess process = message.getSendingProcess();
+
+ // Then
+ assertEquals(mockSendingProcess, process);
+ }
+
+ @Test
+ @DisplayName("Test getLamportTime returns correct time")
+ void testGetLamportTime() {
+ // Given
+ when(mockSendingProcess.getLamportTime()).thenReturn(100L);
+ message.init(mockSendingProcess, "test.Protocol", VSMessage.IS_SERVER_MESSAGE);
+
+ // When
+ long lamportTime = message.getLamportTime();
+
+ // Then
+ assertEquals(100L, lamportTime);
+ }
+
+ @Test
+ @DisplayName("Test getVectorTime returns correct vector time")
+ void testGetVectorTime() {
+ // Given
+ message.init(mockSendingProcess, "test.Protocol", VSMessage.IS_SERVER_MESSAGE);
+
+ // When
+ VSVectorTime vectorTime = message.getVectorTime();
+
+ // Then
+ assertEquals(mockVectorTimeCopy, vectorTime);
+ }
+
+ @Test
+ @DisplayName("Test toString method")
+ void testToString() {
+ // Given
+ String protocolClassname = "test.protocol.MyProtocol";
+ String shortname = "MP";
+ message.init(mockSendingProcess, protocolClassname, VSMessage.IS_SERVER_MESSAGE);
+
+ try (var mockedStatic = mockStatic(VSRegisteredEvents.class)) {
+ mockedStatic.when(() -> VSRegisteredEvents.getShortnameByClassname(protocolClassname))
+ .thenReturn(shortname);
+
+ // When
+ String result = message.toString();
+
+ // Then
+ assertTrue(result.contains("ID: " + message.getMessageID()));
+ assertTrue(result.contains("Protocol"));
+ assertTrue(result.contains(shortname));
+ }
+ }
+
+ @Test
+ @DisplayName("Test toStringFull method includes parent toString")
+ void testToStringFull() {
+ // Given
+ String protocolClassname = "test.protocol.MyProtocol";
+ message.init(mockSendingProcess, protocolClassname, VSMessage.IS_SERVER_MESSAGE);
+
+ // Setup some preferences in the message
+ message.setInteger("test.value", 123);
+
+ // When
+ String result = message.toStringFull();
+
+ // Then
+ assertTrue(result.contains("ID: " + message.getMessageID()));
+ assertTrue(result.contains("test.value"));
+ assertTrue(result.contains("123"));
+ }
+
+ @Test
+ @DisplayName("Test equals method with same message ID")
+ void testEqualsWithSameId() {
+ // Given
+ VSMessage message1 = new VSMessage();
+ VSMessage message2 = message1; // Same reference
+
+ // When/Then
+ assertTrue(message1.equals(message2));
+ }
+
+ @Test
+ @DisplayName("Test equals method with different message IDs")
+ void testEqualsWithDifferentIds() {
+ // Given
+ VSMessage message1 = new VSMessage();
+ VSMessage message2 = new VSMessage();
+
+ // When/Then
+ assertFalse(message1.equals(message2));
+ }
+
+ @Test
+ @DisplayName("Test message inherits VSPrefs functionality")
+ void testPrefsInheritance() {
+ // Given
+ message.init(mockSendingProcess, "test.Protocol", VSMessage.IS_SERVER_MESSAGE);
+
+ // When - Test some VSPrefs methods
+ message.setInteger("test.int", 42);
+ message.setString("test.string", "Hello");
+ message.setBoolean("test.bool", true);
+
+ // Then
+ assertEquals(42, message.getInteger("test.int"));
+ assertEquals("Hello", message.getString("test.string"));
+ assertTrue(message.getBoolean("test.bool"));
+ }
+
+ @Test
+ @DisplayName("Test message initialization captures timestamps at send time")
+ void testTimestampsCapturedAtInit() {
+ // Given
+ when(mockSendingProcess.getLamportTime()).thenReturn(10L);
+ VSVectorTime firstVectorTime = mock(VSVectorTime.class);
+ VSVectorTime firstCopy = mock(VSVectorTime.class);
+ when(mockSendingProcess.getVectorTime()).thenReturn(firstVectorTime);
+ when(firstVectorTime.getCopy()).thenReturn(firstCopy);
+
+ // When - Initialize message
+ message.init(mockSendingProcess, "test.Protocol", VSMessage.IS_SERVER_MESSAGE);
+
+ // Change process times after initialization
+ when(mockSendingProcess.getLamportTime()).thenReturn(20L);
+ VSVectorTime secondVectorTime = mock(VSVectorTime.class);
+ when(mockSendingProcess.getVectorTime()).thenReturn(secondVectorTime);
+
+ // Then - Message should retain original timestamps
+ assertEquals(10L, message.getLamportTime());
+ assertEquals(firstCopy, message.getVectorTime());
+ }
+
+ @Test
+ @DisplayName("Test server message flag")
+ void testServerMessageFlag() {
+ // Given/When - Server message
+ message.init(mockSendingProcess, "test.Protocol", VSMessage.IS_SERVER_MESSAGE);
+
+ // Then
+ assertTrue(message.isServerMessage());
+
+ // Given/When - Client message
+ VSMessage clientMessage = new VSMessage();
+ clientMessage.init(mockSendingProcess, "test.Protocol", VSMessage.IS_CLIENT_MESSAGE);
+
+ // Then
+ assertFalse(clientMessage.isServerMessage());
+ }
+
+ @Test
+ @DisplayName("Test multiple messages can be created with different protocols")
+ void testMultipleMessagesWithDifferentProtocols() {
+ // Given
+ VSMessage message1 = new VSMessage();
+ VSMessage message2 = new VSMessage();
+ VSMessage message3 = new VSMessage();
+
+ // When
+ message1.init(mockSendingProcess, "protocol.One", VSMessage.IS_SERVER_MESSAGE);
+ message2.init(mockSendingProcess, "protocol.Two", VSMessage.IS_CLIENT_MESSAGE);
+ message3.init(mockSendingProcess, "protocol.Three", VSMessage.IS_SERVER_MESSAGE);
+
+ // Then
+ assertEquals("protocol.One", message1.getProtocolClassname());
+ assertEquals("protocol.Two", message2.getProtocolClassname());
+ assertEquals("protocol.Three", message3.getProtocolClassname());
+ assertTrue(message1.isServerMessage());
+ assertFalse(message2.isServerMessage());
+ assertTrue(message3.isServerMessage());
+ }
+} \ No newline at end of file
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
diff --git a/src/test/java/events/VSAbstractEventTest.java b/src/test/java/events/VSAbstractEventTest.java
new file mode 100644
index 0000000..8806f3f
--- /dev/null
+++ b/src/test/java/events/VSAbstractEventTest.java
@@ -0,0 +1,271 @@
+package events;
+
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.*;
+
+import core.VSInternalProcess;
+import exceptions.VSEventNotCopyableException;
+import prefs.VSPrefs;
+import events.implementations.VSProcessCrashEvent;
+import events.implementations.VSProcessRecoverEvent;
+
+/**
+ * Unit tests for VSAbstractEvent class.
+ * Tests the abstract event base class functionality including initialization,
+ * copying, serialization, and name management.
+ *
+ * @author Test Suite
+ */
+public class VSAbstractEventTest {
+
+ @Mock
+ private VSInternalProcess mockProcess;
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ private TestEvent testEvent;
+ private CopyableTestEvent copyableTestEvent;
+
+ /**
+ * Test implementation of VSAbstractEvent for testing abstract methods
+ */
+ private static class TestEvent extends VSAbstractEvent {
+ private boolean initCalled = false;
+ private boolean startCalled = false;
+
+ @Override
+ public void onInit() {
+ initCalled = true;
+ setClassname(getClass().toString());
+ }
+
+ @Override
+ public void onStart() {
+ startCalled = true;
+ }
+
+ @Override
+ protected String createShortname(String savedShortname) {
+ return "TestEvent";
+ }
+
+ public boolean isInitCalled() { return initCalled; }
+ public boolean isStartCalled() { return startCalled; }
+ }
+
+ /**
+ * Copyable test event implementation
+ */
+ private static class CopyableTestEvent extends TestEvent implements VSCopyableEvent {
+ private String customData = "original";
+
+ @Override
+ public void initCopy(VSAbstractEvent copy) {
+ if (copy instanceof CopyableTestEvent) {
+ ((CopyableTestEvent) copy).customData = this.customData;
+ }
+ }
+
+ public String getCustomData() { return customData; }
+ public void setCustomData(String data) { this.customData = data; }
+ }
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ when(mockProcess.getPrefs()).thenReturn(mockPrefs);
+
+ testEvent = new TestEvent();
+ copyableTestEvent = new CopyableTestEvent();
+ }
+
+ @Test
+ void testInitWithProcess() {
+ // Test initialization with process
+ assertNull(testEvent.process);
+ assertNull(testEvent.prefs);
+ assertFalse(testEvent.isInitCalled());
+
+ testEvent.init(mockProcess);
+
+ assertEquals(mockProcess, testEvent.process);
+ assertEquals(mockPrefs, testEvent.prefs);
+ assertTrue(testEvent.isInitCalled());
+
+ // Test that init doesn't run twice
+ testEvent.initCalled = false;
+ testEvent.init(mockProcess);
+ assertFalse(testEvent.isInitCalled());
+ }
+
+ @Test
+ void testInitWithoutProcess() {
+ // Test direct init() call
+ testEvent.init();
+
+ assertTrue(testEvent.isInitCalled());
+ assertNull(testEvent.process);
+ assertNull(testEvent.prefs);
+ }
+
+ @Test
+ void testOnStart() {
+ // Test onStart method
+ assertFalse(testEvent.isStartCalled());
+ testEvent.onStart();
+ assertTrue(testEvent.isStartCalled());
+ }
+
+ @Test
+ void testClassnameHandling() {
+ // Test setClassname with "class " prefix
+ testEvent.setClassname("class events.TestEvent");
+ assertEquals("events.TestEvent", testEvent.getClassname());
+
+ // Test setClassname without prefix
+ testEvent.setClassname("events.AnotherEvent");
+ assertEquals("events.AnotherEvent", testEvent.getClassname());
+ }
+
+ @Test
+ void testGetName() {
+ // Mock the static method behavior by setting classname first
+ testEvent.setClassname("events.implementations.VSProcessCrashEvent");
+
+ // Since VSRegisteredEvents.getNameByClassname is static and not easily mockable,
+ // we'll test that getName() delegates properly
+ String name = testEvent.getName();
+ // The actual name depends on VSRegisteredEvents initialization
+ assertNotNull(testEvent.getClassname());
+ }
+
+ @Test
+ void testShortnameHandling() {
+ // Test with custom shortname
+ testEvent.setShortname("CustomShort");
+ assertEquals("CustomShort", testEvent.getShortname());
+
+ // Test without custom shortname (falls back to registered)
+ TestEvent newEvent = new TestEvent();
+ newEvent.setClassname("events.TestEvent");
+ // Since this event is not registered, getShortname will return null from VSRegisteredEvents
+ String shortname = newEvent.getShortname();
+ // The shortname will be null for unregistered events
+ assertNull(shortname);
+ }
+
+ @Test
+ void testGetProcess() {
+ assertNull(testEvent.getProcess());
+
+ testEvent.init(mockProcess);
+ assertEquals(mockProcess, testEvent.getProcess());
+ }
+
+ @Test
+ void testLog() {
+ testEvent.init(mockProcess);
+
+ String message = "Test log message";
+ testEvent.log(message);
+
+ verify(mockProcess).log(message);
+ }
+
+ @Test
+ void testEquals() {
+ TestEvent event1 = new TestEvent();
+ TestEvent event2 = new TestEvent();
+
+ // Events with same ID should be equal
+ assertTrue(event1.equals(event1));
+
+ // Different events have different IDs by default
+ assertFalse(event1.equals(event2));
+ }
+
+ @Test
+ void testGetCopyForCopyableEvent() throws VSEventNotCopyableException {
+ // Setup for copyable event
+ copyableTestEvent.init(mockProcess);
+ copyableTestEvent.setClassname("events.VSAbstractEventTest$CopyableTestEvent");
+ copyableTestEvent.setShortname("CopyableTest");
+ copyableTestEvent.setCustomData("modified");
+
+ // Since VSRegisteredEvents.createEventInstanceByClassname returns null for unregistered classes,
+ // we expect a NullPointerException when trying to copy
+ assertThrows(NullPointerException.class, () -> {
+ copyableTestEvent.getCopy();
+ });
+ }
+
+ @Test
+ void testGetCopyForNonCopyableEvent() {
+ // Test non-copyable event throws exception
+ testEvent.init(mockProcess);
+ testEvent.setClassname("events.VSAbstractEventTest$TestEvent");
+ testEvent.setShortname("Test");
+
+ assertThrows(VSEventNotCopyableException.class, () -> {
+ testEvent.getCopy();
+ });
+ }
+
+ @Test
+ void testGetCopyWithDifferentProcess() throws VSEventNotCopyableException {
+ VSInternalProcess newProcess = mock(VSInternalProcess.class);
+ when(newProcess.getPrefs()).thenReturn(mockPrefs);
+
+ copyableTestEvent.init(mockProcess);
+ copyableTestEvent.setClassname("events.VSAbstractEventTest$CopyableTestEvent");
+
+ // Since VSRegisteredEvents.createEventInstanceByClassname returns null for unregistered classes,
+ // we expect a NullPointerException
+ assertThrows(NullPointerException.class, () -> {
+ copyableTestEvent.getCopy(newProcess);
+ });
+ }
+
+ @Test
+ void testGetCopyWithNullProcess() throws VSEventNotCopyableException {
+ copyableTestEvent.init(mockProcess);
+ copyableTestEvent.setClassname("events.VSAbstractEventTest$CopyableTestEvent");
+
+ // When null is passed, it should use the current process
+ // Since VSRegisteredEvents.createEventInstanceByClassname returns null for unregistered classes,
+ // we expect a NullPointerException
+ assertThrows(NullPointerException.class, () -> {
+ copyableTestEvent.getCopy(null);
+ });
+ }
+
+ @Test
+ void testCreateShortname() {
+ // Test the abstract createShortname method implementation
+ String shortname = testEvent.createShortname("SavedName");
+ assertEquals("TestEvent", shortname);
+ }
+
+ @Test
+ void testRealEventImplementations() {
+ // Test with actual event implementations
+ VSProcessCrashEvent crashEvent = new VSProcessCrashEvent();
+ VSProcessRecoverEvent recoverEvent = new VSProcessRecoverEvent();
+
+ // Test that they implement VSCopyableEvent
+ assertTrue(crashEvent instanceof VSCopyableEvent);
+ assertTrue(recoverEvent instanceof VSCopyableEvent);
+
+ // Test initialization
+ crashEvent.init(mockProcess);
+ recoverEvent.init(mockProcess);
+
+ assertNotNull(crashEvent.getClassname());
+ assertNotNull(recoverEvent.getClassname());
+ }
+} \ No newline at end of file
diff --git a/src/test/java/events/VSRegisteredEventsTest.java b/src/test/java/events/VSRegisteredEventsTest.java
new file mode 100644
index 0000000..0f20f25
--- /dev/null
+++ b/src/test/java/events/VSRegisteredEventsTest.java
@@ -0,0 +1,324 @@
+package events;
+
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.Vector;
+
+import core.VSInternalProcess;
+import prefs.VSPrefs;
+import events.implementations.VSProcessCrashEvent;
+import events.implementations.VSProcessRecoverEvent;
+
+/**
+ * Unit tests for VSRegisteredEvents class.
+ * Tests event registration, lookup, instantiation, and protocol management.
+ *
+ * @author Test Suite
+ */
+public class VSRegisteredEventsTest {
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ @Mock
+ private VSInternalProcess mockProcess;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ // Use a default answer to return empty string for any unmocked calls
+ when(mockPrefs.getString(anyString())).thenAnswer(invocation -> {
+ String key = invocation.getArgument(0);
+ // Return a default value based on the key pattern
+ if (key.endsWith(".short")) {
+ return "DefaultShort";
+ }
+ return "Default Event/Protocol";
+ });
+
+ // Now override with specific values we want to test
+ // Events
+ when(mockPrefs.getString("lang.events.implementations.VSProcessCrashEvent"))
+ .thenReturn("Process Crash");
+ when(mockPrefs.getString("lang.events.implementations.VSProcessCrashEvent.short"))
+ .thenReturn("Crash");
+ when(mockPrefs.getString("lang.events.implementations.VSProcessRecoverEvent"))
+ .thenReturn("Process Recover");
+ when(mockPrefs.getString("lang.events.implementations.VSProcessRecoverEvent.short"))
+ .thenReturn("Recover");
+
+ // Protocols - mock key protocols we'll test
+ when(mockPrefs.getString("lang.protocols.implementations.VSPingPongProtocol"))
+ .thenReturn("Ping Pong Protocol");
+ when(mockPrefs.getString("lang.protocols.implementations.VSPingPongProtocol.short"))
+ .thenReturn("PingPong");
+ when(mockPrefs.getString("lang.protocols.implementations.VSDummyProtocol"))
+ .thenReturn("Dummy Protocol");
+ when(mockPrefs.getString("lang.protocols.implementations.VSDummyProtocol.short"))
+ .thenReturn("Dummy");
+
+ // Initialize the registered events
+ VSRegisteredEvents.init(mockPrefs);
+ }
+
+ @Test
+ void testGetClassnameByEventname() {
+ // Test that we can retrieve classnames by event names
+ String classname = VSRegisteredEvents.getClassnameByEventname("Process Crash");
+ assertEquals("events.implementations.VSProcessCrashEvent", classname);
+
+ classname = VSRegisteredEvents.getClassnameByEventname("Process Recover");
+ assertEquals("events.implementations.VSProcessRecoverEvent", classname);
+
+ // Test non-existent event
+ classname = VSRegisteredEvents.getClassnameByEventname("Non Existent Event");
+ assertNull(classname);
+ }
+
+ @Test
+ void testGetNameByClassname() {
+ // Test retrieving names by classnames
+ String name = VSRegisteredEvents.getNameByClassname(
+ "events.implementations.VSProcessCrashEvent");
+ assertEquals("Process Crash", name);
+
+ name = VSRegisteredEvents.getNameByClassname(
+ "events.implementations.VSProcessRecoverEvent");
+ assertEquals("Process Recover", name);
+
+ // Test non-existent classname
+ name = VSRegisteredEvents.getNameByClassname("non.existent.Class");
+ assertNull(name);
+ }
+
+ @Test
+ void testGetShortnameByClassname() {
+ // Test retrieving shortnames by classnames
+ String shortname = VSRegisteredEvents.getShortnameByClassname(
+ "events.implementations.VSProcessCrashEvent");
+ assertEquals("Crash", shortname);
+
+ shortname = VSRegisteredEvents.getShortnameByClassname(
+ "events.implementations.VSProcessRecoverEvent");
+ assertEquals("Recover", shortname);
+
+ // Test non-existent classname
+ shortname = VSRegisteredEvents.getShortnameByClassname("non.existent.Class");
+ assertNull(shortname);
+ }
+
+ @Test
+ void testGetClassnameByShortname() {
+ // Test retrieving classnames by shortnames
+ String classname = VSRegisteredEvents.getClassnameByShortname("Crash");
+ assertEquals("events.implementations.VSProcessCrashEvent", classname);
+
+ classname = VSRegisteredEvents.getClassnameByShortname("Recover");
+ assertEquals("events.implementations.VSProcessRecoverEvent", classname);
+
+ // Test non-existent shortname
+ classname = VSRegisteredEvents.getClassnameByShortname("NonExistent");
+ assertNull(classname);
+ }
+
+ @Test
+ void testCreateEventInstanceByClassname() {
+ when(mockProcess.getPrefs()).thenReturn(mockPrefs);
+
+ // Test creating VSProcessCrashEvent
+ VSAbstractEvent event = VSRegisteredEvents.createEventInstanceByClassname(
+ "events.implementations.VSProcessCrashEvent", mockProcess);
+
+ assertNotNull(event);
+ assertTrue(event instanceof VSProcessCrashEvent);
+ assertEquals(mockProcess, event.getProcess());
+ assertNotNull(event.getClassname());
+
+ // Test creating VSProcessRecoverEvent
+ event = VSRegisteredEvents.createEventInstanceByClassname(
+ "events.implementations.VSProcessRecoverEvent", mockProcess);
+
+ assertNotNull(event);
+ assertTrue(event instanceof VSProcessRecoverEvent);
+
+ // Test with invalid classname
+ event = VSRegisteredEvents.createEventInstanceByClassname(
+ "non.existent.Class", mockProcess);
+ assertNull(event);
+ }
+
+ @Test
+ void testCreateEventInstanceByName() {
+ when(mockProcess.getPrefs()).thenReturn(mockPrefs);
+
+ // Test creating event by name
+ VSAbstractEvent event = VSRegisteredEvents.createEventInstanceByName(
+ "Process Crash", mockProcess);
+
+ assertNotNull(event);
+ assertTrue(event instanceof VSProcessCrashEvent);
+
+ // Test with non-existent name
+ event = VSRegisteredEvents.createEventInstanceByName(
+ "Non Existent Event", mockProcess);
+ assertNull(event);
+ }
+
+ @Test
+ void testGetProtocolNames() {
+ // Test getting protocol names (sorted)
+ Vector<String> protocolNames = VSRegisteredEvents.getProtocolNames();
+
+ assertNotNull(protocolNames);
+ assertFalse(protocolNames.isEmpty());
+
+ // Check that it contains protocol names
+ assertTrue(protocolNames.contains("Ping Pong Protocol"));
+ assertTrue(protocolNames.contains("Dummy Protocol"));
+
+ // Verify they are sorted
+ for (int i = 1; i < protocolNames.size(); i++) {
+ assertTrue(protocolNames.get(i-1).compareTo(protocolNames.get(i)) <= 0);
+ }
+ }
+
+ @Test
+ void testGetProtocolClassnames() {
+ // Test getting protocol classnames
+ Vector<String> protocolClassnames = VSRegisteredEvents.getProtocolClassnames();
+
+ assertNotNull(protocolClassnames);
+ assertFalse(protocolClassnames.isEmpty());
+
+ // Check that all returned classnames start with protocols.implementations
+ for (String classname : protocolClassnames) {
+ assertTrue(classname.startsWith("protocols.implementations"));
+ }
+ }
+
+ @Test
+ void testGetNonProtocolNames() {
+ // Test getting non-protocol event names (sorted)
+ Vector<String> eventNames = VSRegisteredEvents.getNonProtocolNames();
+
+ assertNotNull(eventNames);
+ assertFalse(eventNames.isEmpty());
+
+ // Check that it contains event names
+ assertTrue(eventNames.contains("Process Crash"));
+ assertTrue(eventNames.contains("Process Recover"));
+
+ // Verify they are sorted
+ for (int i = 1; i < eventNames.size(); i++) {
+ assertTrue(eventNames.get(i-1).compareTo(eventNames.get(i)) <= 0);
+ }
+ }
+
+ @Test
+ void testGetNonProtocolClassnames() {
+ // Test getting non-protocol event classnames
+ Vector<String> eventClassnames = VSRegisteredEvents.getNonProtocolClassnames();
+
+ assertNotNull(eventClassnames);
+ assertFalse(eventClassnames.isEmpty());
+
+ // Check that all returned classnames start with events.implementations
+ for (String classname : eventClassnames) {
+ assertTrue(classname.startsWith("events.implementations"));
+ }
+
+ // Check specific events are included
+ assertTrue(eventClassnames.contains("events.implementations.VSProcessCrashEvent"));
+ assertTrue(eventClassnames.contains("events.implementations.VSProcessRecoverEvent"));
+
+ // Verify they are sorted
+ for (int i = 1; i < eventClassnames.size(); i++) {
+ assertTrue(eventClassnames.get(i-1).compareTo(eventClassnames.get(i)) <= 0);
+ }
+ }
+
+ @Test
+ void testGetEditableProtocolsClassnames() {
+ // Test getting editable protocols
+ ArrayList<String> editableProtocols =
+ VSRegisteredEvents.getEditableProtocolsClassnames();
+
+ assertNotNull(editableProtocols);
+ // The actual content depends on which protocols have editable variables
+ // Just verify the list is created
+ }
+
+ @Test
+ void testGetProtocolServerVariables() {
+ // Test getting server variables for a protocol
+ // This would normally return variables if the protocol has them
+ ArrayList<String> serverVars = VSRegisteredEvents.getProtocolServerVariables(
+ "protocols.implementations.VSDummyProtocol");
+
+ // May be null if protocol has no server variables
+ // Just test the method doesn't throw
+ }
+
+ @Test
+ void testGetProtocolClientVariables() {
+ // Test getting client variables for a protocol
+ ArrayList<String> clientVars = VSRegisteredEvents.getProtocolClientVariables(
+ "protocols.implementations.VSDummyProtocol");
+
+ // May be null if protocol has no client variables
+ // Just test the method doesn't throw
+ }
+
+ @Test
+ void testIsOnServerStartProtocol() {
+ // Test checking if protocol uses onServerStart
+ // Default should be false for protocols not explicitly marked
+ boolean isServerStart = VSRegisteredEvents.isOnServerStartProtocol(
+ "protocols.implementations.VSDummyProtocol");
+
+ // Just verify the method works
+ assertTrue(isServerStart == true || isServerStart == false);
+
+ // Test with non-existent protocol
+ assertFalse(VSRegisteredEvents.isOnServerStartProtocol("non.existent.Protocol"));
+ }
+
+ @Test
+ void testEventRegistrationIntegrity() {
+ // Test that events are properly registered with all mappings
+ String testClassname = "events.implementations.VSProcessCrashEvent";
+ String testName = "Process Crash";
+ String testShortname = "Crash";
+
+ // Verify all mappings work correctly
+ assertEquals(testClassname, VSRegisteredEvents.getClassnameByEventname(testName));
+ assertEquals(testName, VSRegisteredEvents.getNameByClassname(testClassname));
+ assertEquals(testShortname, VSRegisteredEvents.getShortnameByClassname(testClassname));
+ assertEquals(testClassname, VSRegisteredEvents.getClassnameByShortname(testShortname));
+ }
+
+ @Test
+ void testProtocolEventSeparation() {
+ // Test that protocols and events are properly separated
+ Vector<String> protocols = VSRegisteredEvents.getProtocolClassnames();
+ Vector<String> events = VSRegisteredEvents.getNonProtocolClassnames();
+
+ // Verify no overlap between protocols and events
+ for (String protocol : protocols) {
+ assertFalse(events.contains(protocol));
+ assertTrue(protocol.startsWith("protocols.implementations"));
+ }
+
+ for (String event : events) {
+ assertFalse(protocols.contains(event));
+ assertTrue(event.startsWith("events.implementations"));
+ }
+ }
+} \ No newline at end of file
diff --git a/src/test/java/events/implementations/VSProcessCrashEventTest.java b/src/test/java/events/implementations/VSProcessCrashEventTest.java
new file mode 100644
index 0000000..91a27cb
--- /dev/null
+++ b/src/test/java/events/implementations/VSProcessCrashEventTest.java
@@ -0,0 +1,198 @@
+package events.implementations;
+
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.*;
+
+import core.VSInternalProcess;
+import events.VSAbstractEvent;
+import events.VSCopyableEvent;
+import prefs.VSPrefs;
+import simulator.VSMain;
+
+/**
+ * Unit tests for VSProcessCrashEvent.
+ * Tests the process crash event functionality including initialization,
+ * execution, and copying behavior.
+ *
+ * @author Test Suite
+ */
+public class VSProcessCrashEventTest {
+
+ @Mock
+ private VSInternalProcess mockProcess;
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ @Mock
+ private VSPrefs mockMainPrefs;
+
+ private VSProcessCrashEvent crashEvent;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ // Setup mocks
+ when(mockProcess.getPrefs()).thenReturn(mockPrefs);
+ when(mockPrefs.getString("lang.crashed")).thenReturn("Process has crashed");
+ when(mockMainPrefs.getString("lang.process.crash")).thenReturn("Crash");
+
+ // Mock VSMain.prefs for shortname creation
+ VSMain.prefs = mockMainPrefs;
+
+ crashEvent = new VSProcessCrashEvent();
+ }
+
+ @Test
+ void testImplementsVSCopyableEvent() {
+ // Verify that VSProcessCrashEvent implements VSCopyableEvent
+ assertTrue(crashEvent instanceof VSCopyableEvent);
+ }
+
+ @Test
+ void testOnInit() {
+ // Test initialization
+ assertNull(crashEvent.getClassname());
+
+ crashEvent.onInit();
+
+ assertNotNull(crashEvent.getClassname());
+ assertTrue(crashEvent.getClassname().contains("VSProcessCrashEvent"));
+ }
+
+ @Test
+ void testCreateShortname() {
+ // Test shortname creation
+ String shortname = crashEvent.createShortname("SavedCrash");
+ assertEquals("Crash", shortname);
+
+ // Test that it uses VSMain.prefs
+ verify(mockMainPrefs).getString("lang.process.crash");
+ }
+
+ @Test
+ void testOnStartWhenProcessNotCrashed() {
+ // Setup process as not crashed
+ when(mockProcess.isCrashed()).thenReturn(false);
+
+ // Initialize the event with process
+ crashEvent.init(mockProcess);
+
+ // Execute the event
+ crashEvent.onStart();
+
+ // Verify process was set to crashed
+ verify(mockProcess).isCrashed(true);
+ verify(mockProcess).log("Process has crashed");
+ }
+
+ @Test
+ void testOnStartWhenProcessAlreadyCrashed() {
+ // Setup process as already crashed
+ when(mockProcess.isCrashed()).thenReturn(true);
+
+ // Initialize the event with process
+ crashEvent.init(mockProcess);
+
+ // Execute the event
+ crashEvent.onStart();
+
+ // Verify process crash state was not changed
+ verify(mockProcess, never()).isCrashed(true);
+ verify(mockProcess, never()).log(anyString());
+ }
+
+ @Test
+ void testInitCopy() {
+ // Test the copy initialization
+ VSProcessCrashEvent copyEvent = new VSProcessCrashEvent();
+
+ // This method should do nothing for VSProcessCrashEvent
+ crashEvent.initCopy(copyEvent);
+
+ // Verify no exceptions thrown and copy is still valid
+ assertNotNull(copyEvent);
+ }
+
+ @Test
+ void testFullEventLifecycle() {
+ // Test complete event lifecycle
+
+ // 1. Create and initialize event
+ VSProcessCrashEvent event = new VSProcessCrashEvent();
+ event.init(mockProcess);
+
+ // 2. Verify initialization
+ assertEquals(mockProcess, event.getProcess());
+ assertEquals(mockPrefs, event.prefs);
+ assertNotNull(event.getClassname());
+
+ // 3. Setup process state
+ when(mockProcess.isCrashed()).thenReturn(false);
+
+ // 4. Execute event
+ event.onStart();
+
+ // 5. Verify execution results
+ verify(mockProcess).isCrashed(true);
+ verify(mockProcess).log("Process has crashed");
+ }
+
+ @Test
+ void testEventWithNullProcess() {
+ // Test behavior when process is not set
+ crashEvent.onInit();
+
+ // Should throw NullPointerException when accessing process
+ assertThrows(NullPointerException.class, () -> {
+ crashEvent.onStart();
+ });
+ }
+
+ @Test
+ void testGetCopyFunctionality() {
+ // Initialize the event
+ crashEvent.init(mockProcess);
+ crashEvent.setClassname("events.implementations.VSProcessCrashEvent");
+ crashEvent.setShortname("Crash");
+
+ // Since this implements VSCopyableEvent, getCopy should work
+ // (though it will fail in unit test due to VSRegisteredEvents static dependencies)
+ assertDoesNotThrow(() -> {
+ try {
+ crashEvent.getCopy();
+ } catch (Exception e) {
+ // Expected in unit test environment
+ }
+ });
+ }
+
+ @Test
+ void testEventEquality() {
+ // Test event equality based on ID
+ VSProcessCrashEvent event1 = new VSProcessCrashEvent();
+ VSProcessCrashEvent event2 = new VSProcessCrashEvent();
+
+ // Same event should equal itself
+ assertTrue(event1.equals(event1));
+
+ // Different instances have different IDs
+ assertFalse(event1.equals(event2));
+ }
+
+ @Test
+ void testLogging() {
+ // Test logging functionality
+ crashEvent.init(mockProcess);
+
+ String testMessage = "Test log message";
+ crashEvent.log(testMessage);
+
+ verify(mockProcess).log(testMessage);
+ }
+} \ No newline at end of file
diff --git a/src/test/java/events/implementations/VSProcessRecoverEventTest.java b/src/test/java/events/implementations/VSProcessRecoverEventTest.java
new file mode 100644
index 0000000..3004ba2
--- /dev/null
+++ b/src/test/java/events/implementations/VSProcessRecoverEventTest.java
@@ -0,0 +1,236 @@
+package events.implementations;
+
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.*;
+
+import core.VSInternalProcess;
+import events.VSAbstractEvent;
+import events.VSCopyableEvent;
+import prefs.VSPrefs;
+import simulator.VSMain;
+
+/**
+ * Unit tests for VSProcessRecoverEvent.
+ * Tests the process recovery event functionality including initialization,
+ * execution, and copying behavior.
+ *
+ * @author Test Suite
+ */
+public class VSProcessRecoverEventTest {
+
+ @Mock
+ private VSInternalProcess mockProcess;
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ @Mock
+ private VSPrefs mockMainPrefs;
+
+ private VSProcessRecoverEvent recoverEvent;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ // Setup mocks
+ when(mockProcess.getPrefs()).thenReturn(mockPrefs);
+ when(mockPrefs.getString("lang.recovered")).thenReturn("Process has recovered");
+ when(mockMainPrefs.getString("lang.process.recover")).thenReturn("Recover");
+
+ // Mock VSMain.prefs for shortname creation
+ VSMain.prefs = mockMainPrefs;
+
+ recoverEvent = new VSProcessRecoverEvent();
+ }
+
+ @Test
+ void testImplementsVSCopyableEvent() {
+ // Verify that VSProcessRecoverEvent implements VSCopyableEvent
+ assertTrue(recoverEvent instanceof VSCopyableEvent);
+ }
+
+ @Test
+ void testOnInit() {
+ // Test initialization
+ assertNull(recoverEvent.getClassname());
+
+ recoverEvent.onInit();
+
+ assertNotNull(recoverEvent.getClassname());
+ assertTrue(recoverEvent.getClassname().contains("VSProcessRecoverEvent"));
+ }
+
+ @Test
+ void testCreateShortname() {
+ // Test shortname creation
+ String shortname = recoverEvent.createShortname("SavedRecover");
+ assertEquals("Recover", shortname);
+
+ // Test that it uses VSMain.prefs
+ verify(mockMainPrefs).getString("lang.process.recover");
+ }
+
+ @Test
+ void testOnStartWhenProcessIsCrashed() {
+ // Setup process as crashed
+ when(mockProcess.isCrashed()).thenReturn(true);
+
+ // Initialize the event with process
+ recoverEvent.init(mockProcess);
+
+ // Execute the event
+ recoverEvent.onStart();
+
+ // Verify process was recovered
+ verify(mockProcess).isCrashed(false);
+ verify(mockProcess).log("Process has recovered");
+ }
+
+ @Test
+ void testOnStartWhenProcessNotCrashed() {
+ // Setup process as not crashed (already running)
+ when(mockProcess.isCrashed()).thenReturn(false);
+
+ // Initialize the event with process
+ recoverEvent.init(mockProcess);
+
+ // Execute the event
+ recoverEvent.onStart();
+
+ // Verify process state was not changed
+ verify(mockProcess, never()).isCrashed(false);
+ verify(mockProcess, never()).log(anyString());
+ }
+
+ @Test
+ void testInitCopy() {
+ // Test the copy initialization
+ VSProcessRecoverEvent copyEvent = new VSProcessRecoverEvent();
+
+ // This method should do nothing for VSProcessRecoverEvent
+ recoverEvent.initCopy(copyEvent);
+
+ // Verify no exceptions thrown and copy is still valid
+ assertNotNull(copyEvent);
+ }
+
+ @Test
+ void testFullEventLifecycle() {
+ // Test complete event lifecycle
+
+ // 1. Create and initialize event
+ VSProcessRecoverEvent event = new VSProcessRecoverEvent();
+ event.init(mockProcess);
+
+ // 2. Verify initialization
+ assertEquals(mockProcess, event.getProcess());
+ assertEquals(mockPrefs, event.prefs);
+ assertNotNull(event.getClassname());
+
+ // 3. Setup process state as crashed
+ when(mockProcess.isCrashed()).thenReturn(true);
+
+ // 4. Execute event
+ event.onStart();
+
+ // 5. Verify execution results
+ verify(mockProcess).isCrashed(false);
+ verify(mockProcess).log("Process has recovered");
+ }
+
+ @Test
+ void testEventWithNullProcess() {
+ // Test behavior when process is not set
+ recoverEvent.onInit();
+
+ // Should throw NullPointerException when accessing process
+ assertThrows(NullPointerException.class, () -> {
+ recoverEvent.onStart();
+ });
+ }
+
+ @Test
+ void testComplementaryBehaviorWithCrashEvent() {
+ // Test that recover event properly complements crash event
+ VSProcessCrashEvent crashEvent = new VSProcessCrashEvent();
+
+ // Initialize both events
+ crashEvent.init(mockProcess);
+ recoverEvent.init(mockProcess);
+
+ // Simulate crash then recover sequence
+ when(mockProcess.isCrashed()).thenReturn(false).thenReturn(true);
+
+ // Crash the process
+ crashEvent.onStart();
+ verify(mockProcess).isCrashed(true);
+
+ // Recover the process
+ recoverEvent.onStart();
+ verify(mockProcess).isCrashed(false);
+ }
+
+ @Test
+ void testGetCopyFunctionality() {
+ // Initialize the event
+ recoverEvent.init(mockProcess);
+ recoverEvent.setClassname("events.implementations.VSProcessRecoverEvent");
+ recoverEvent.setShortname("Recover");
+
+ // Since this implements VSCopyableEvent, getCopy should work
+ // (though it will fail in unit test due to VSRegisteredEvents static dependencies)
+ assertDoesNotThrow(() -> {
+ try {
+ recoverEvent.getCopy();
+ } catch (Exception e) {
+ // Expected in unit test environment
+ }
+ });
+ }
+
+ @Test
+ void testEventEquality() {
+ // Test event equality based on ID
+ VSProcessRecoverEvent event1 = new VSProcessRecoverEvent();
+ VSProcessRecoverEvent event2 = new VSProcessRecoverEvent();
+
+ // Same event should equal itself
+ assertTrue(event1.equals(event1));
+
+ // Different instances have different IDs
+ assertFalse(event1.equals(event2));
+ }
+
+ @Test
+ void testLogging() {
+ // Test logging functionality
+ recoverEvent.init(mockProcess);
+
+ String testMessage = "Test recovery message";
+ recoverEvent.log(testMessage);
+
+ verify(mockProcess).log(testMessage);
+ }
+
+ @Test
+ void testMultipleRecoveryAttempts() {
+ // Test multiple recovery attempts on already running process
+ when(mockProcess.isCrashed()).thenReturn(false);
+
+ recoverEvent.init(mockProcess);
+
+ // Try to recover multiple times
+ recoverEvent.onStart();
+ recoverEvent.onStart();
+ recoverEvent.onStart();
+
+ // Verify no state changes or logs
+ verify(mockProcess, never()).isCrashed(false);
+ verify(mockProcess, never()).log(anyString());
+ }
+} \ No newline at end of file
diff --git a/src/test/java/protocols/VSAbstractProtocolTest.java b/src/test/java/protocols/VSAbstractProtocolTest.java
new file mode 100644
index 0000000..28b2fc2
--- /dev/null
+++ b/src/test/java/protocols/VSAbstractProtocolTest.java
@@ -0,0 +1,368 @@
+package protocols;
+
+import core.VSInternalProcess;
+import core.VSMessage;
+import core.VSMessageStub;
+import core.VSTask;
+import events.internal.VSProtocolScheduleEvent;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import prefs.VSPrefs;
+import simulator.VSSimulatorVisualization;
+import core.VSTaskManager;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+/**
+ * Unit tests for VSAbstractProtocol.
+ */
+class VSAbstractProtocolTest {
+
+ @Mock
+ private VSInternalProcess mockProcess;
+
+ @Mock
+ private VSSimulatorVisualization mockCanvas;
+
+ @Mock
+ private VSTaskManager mockTaskManager;
+
+ @Mock
+ private VSMessage mockMessage;
+
+ @Mock
+ private VSMessageStub mockMessageStub;
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ @Mock
+ private ObjectOutputStream mockOutputStream;
+
+ @Mock
+ private ObjectInputStream mockInputStream;
+
+ private TestProtocol testProtocol;
+
+ /**
+ * Test implementation of VSAbstractProtocol.
+ */
+ private static class TestProtocol extends VSAbstractProtocol {
+ boolean clientInitCalled = false;
+ boolean serverInitCalled = false;
+ boolean clientResetCalled = false;
+ boolean serverResetCalled = false;
+ boolean clientScheduleCalled = false;
+ boolean serverScheduleCalled = false;
+ boolean clientRecvCalled = false;
+ boolean serverRecvCalled = false;
+ VSMessage lastClientMessage = null;
+ VSMessage lastServerMessage = null;
+
+ TestProtocol(boolean hasOnServerStart) {
+ super(hasOnServerStart);
+ }
+
+ @Override
+ public void onClientInit() {
+ clientInitCalled = true;
+ }
+
+ @Override
+ public void onClientReset() {
+ clientResetCalled = true;
+ }
+
+ @Override
+ public void onClientSchedule() {
+ clientScheduleCalled = true;
+ }
+
+ @Override
+ public void onClientRecv(VSMessage message) {
+ clientRecvCalled = true;
+ lastClientMessage = message;
+ }
+
+ @Override
+ public void onServerInit() {
+ serverInitCalled = true;
+ }
+
+ @Override
+ public void onServerReset() {
+ serverResetCalled = true;
+ }
+
+ @Override
+ public void onServerRecv(VSMessage message) {
+ serverRecvCalled = true;
+ lastServerMessage = message;
+ }
+
+ @Override
+ public void onServerSchedule() {
+ serverScheduleCalled = true;
+ }
+ }
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ testProtocol = new TestProtocol(true);
+
+ // Setup mock chain
+ when(mockProcess.getSimulatorCanvas()).thenReturn(mockCanvas);
+ when(mockCanvas.getTaskManager()).thenReturn(mockTaskManager);
+ when(mockCanvas.getNumProcesses()).thenReturn(5);
+ when(mockPrefs.getString(anyString())).thenReturn("TestString");
+
+ testProtocol.prefs = mockPrefs;
+ }
+
+ @Test
+ void testConstructor() {
+ TestProtocol serverStartProtocol = new TestProtocol(true);
+ assertTrue(serverStartProtocol.hasOnServerStart());
+
+ TestProtocol clientStartProtocol = new TestProtocol(false);
+ assertFalse(clientStartProtocol.hasOnServerStart());
+ }
+
+ @Test
+ void testServerClientFlags() {
+ assertFalse(testProtocol.isServer());
+ assertFalse(testProtocol.isClient());
+
+ testProtocol.isServer(true);
+ assertTrue(testProtocol.isServer());
+
+ testProtocol.isClient(true);
+ assertTrue(testProtocol.isClient());
+ }
+
+ @Test
+ void testSendMessage() {
+ testProtocol.process = mockProcess;
+ testProtocol.currentContextIsServer(true);
+
+ testProtocol.sendMessage(mockMessage);
+
+ verify(mockProcess).increaseLamportTime();
+ verify(mockProcess).increaseVectorTime();
+ verify(mockProcess).sendMessage(mockMessage);
+ }
+
+ @Test
+ void testSendMessageWithNullProcess() {
+ testProtocol.process = null;
+
+ // Should not throw exception
+ assertDoesNotThrow(() -> testProtocol.sendMessage(mockMessage));
+
+ // Should not interact with anything
+ verifyNoInteractions(mockProcess);
+ }
+
+ @Test
+ void testOnStartWithServerMode() {
+ testProtocol = new TestProtocol(true); // Has server start
+ testProtocol.process = mockProcess;
+ testProtocol.isServer(true);
+ testProtocol.prefs = mockPrefs;
+
+ testProtocol.onStart();
+
+ assertTrue(testProtocol.serverInitCalled);
+ assertFalse(testProtocol.clientInitCalled);
+ }
+
+ @Test
+ void testOnStartWithClientMode() {
+ testProtocol = new TestProtocol(false); // Has client start
+ testProtocol.process = mockProcess;
+ testProtocol.isClient(true);
+ testProtocol.prefs = mockPrefs;
+
+ testProtocol.onStart();
+
+ assertTrue(testProtocol.clientInitCalled);
+ assertFalse(testProtocol.serverInitCalled);
+ }
+
+ @Test
+ void testOnInit() {
+ testProtocol.process = mockProcess;
+ testProtocol.isServer(true);
+ testProtocol.isClient(true);
+
+ testProtocol.onInit();
+
+ assertTrue(testProtocol.serverInitCalled);
+ assertTrue(testProtocol.clientInitCalled);
+ }
+
+ @Test
+ void testOnMessageRecvWithCorrectProtocol() {
+ when(mockMessage.getProtocolClassname()).thenReturn(testProtocol.getClassname());
+ when(mockMessage.isServerMessage()).thenReturn(false); // Client message
+
+ testProtocol.process = mockProcess;
+ testProtocol.isServer(true);
+
+ testProtocol.onMessageRecvStart(mockMessage);
+
+ assertTrue(testProtocol.serverRecvCalled);
+ assertEquals(mockMessage, testProtocol.lastServerMessage);
+ }
+
+ @Test
+ void testOnMessageRecvWithIncorrectProtocol() {
+ when(mockMessage.getProtocolClassname()).thenReturn("DifferentProtocol");
+
+ testProtocol.process = mockProcess;
+ testProtocol.isServer(true);
+
+ testProtocol.onMessageRecvStart(mockMessage);
+
+ assertFalse(testProtocol.serverRecvCalled);
+ assertNull(testProtocol.lastServerMessage);
+ }
+
+ @Test
+ void testIsRelevantMessage() {
+ when(mockMessage.getProtocolClassname()).thenReturn(testProtocol.getClassname());
+
+ // Server receiving client message - should be relevant
+ when(mockMessage.isServerMessage()).thenReturn(false);
+ testProtocol.isServer(true);
+ testProtocol.isClient(false);
+ assertTrue(testProtocol.isRelevantMessage(mockMessage));
+
+ // Client receiving server message - should be relevant
+ when(mockMessage.isServerMessage()).thenReturn(true);
+ testProtocol.isServer(false);
+ testProtocol.isClient(true);
+ assertTrue(testProtocol.isRelevantMessage(mockMessage));
+
+ // Server receiving server message - should NOT be relevant
+ when(mockMessage.isServerMessage()).thenReturn(true);
+ testProtocol.isServer(true);
+ testProtocol.isClient(false);
+ assertFalse(testProtocol.isRelevantMessage(mockMessage));
+ }
+
+ @Test
+ void testScheduleAt() {
+ testProtocol.process = mockProcess;
+ testProtocol.currentContextIsServer(true);
+
+ long scheduleTime = 100L;
+ testProtocol.scheduleAt(scheduleTime);
+
+ ArgumentCaptor<VSTask> taskCaptor = ArgumentCaptor.forClass(VSTask.class);
+ verify(mockTaskManager).addTask(taskCaptor.capture());
+
+ VSTask capturedTask = taskCaptor.getValue();
+ assertNotNull(capturedTask);
+ assertEquals(mockProcess, capturedTask.getProcess());
+ }
+
+ @Test
+ void testRemoveSchedules() {
+ testProtocol.process = mockProcess;
+ testProtocol.currentContextIsServer(true);
+
+ // First add a schedule
+ testProtocol.scheduleAt(100L);
+
+ // Then remove it
+ testProtocol.removeSchedules();
+
+ verify(mockTaskManager).removeAllTasks(any());
+ }
+
+ @Test
+ void testReset() {
+ testProtocol.isServer(true);
+ testProtocol.isClient(true);
+
+ testProtocol.reset();
+
+ assertFalse(testProtocol.isServer());
+ assertFalse(testProtocol.isClient());
+ assertTrue(testProtocol.serverResetCalled);
+ assertTrue(testProtocol.clientResetCalled);
+ }
+
+ @Test
+ void testGetNumProcesses() {
+ testProtocol.process = mockProcess;
+
+ assertEquals(5, testProtocol.getNumProcesses());
+
+ testProtocol.process = null;
+ assertEquals(0, testProtocol.getNumProcesses());
+ }
+
+ @Test
+ void testToString() {
+ testProtocol.process = mockProcess;
+ testProtocol.currentContextIsServer(true);
+
+ String result = testProtocol.toString();
+
+ assertNotNull(result);
+ assertTrue(result.contains("TestString"));
+
+ // Test with null process
+ testProtocol.process = null;
+ assertEquals("", testProtocol.toString());
+ }
+
+ @Test
+ void testOnClientScheduleStart() {
+ testProtocol.isClient(true);
+
+ testProtocol.onClientScheduleStart();
+
+ assertTrue(testProtocol.clientScheduleCalled);
+ assertFalse(testProtocol.serverScheduleCalled);
+ }
+
+ @Test
+ void testOnServerScheduleStart() {
+ testProtocol.isServer(true);
+
+ testProtocol.onServerScheduleStart();
+
+ assertTrue(testProtocol.serverScheduleCalled);
+ assertFalse(testProtocol.clientScheduleCalled);
+ }
+
+ @Test
+ void testSerialization() throws IOException, ClassNotFoundException {
+ testProtocol.serialize(null, mockOutputStream);
+
+ verify(mockOutputStream, times(2)).writeObject(Boolean.FALSE);
+ verify(mockOutputStream).writeObject(Boolean.TRUE); // hasOnServerStart
+ }
+
+ @Test
+ void testDeserialization() throws IOException, ClassNotFoundException {
+ when(mockInputStream.readObject()).thenReturn(Boolean.FALSE, Boolean.TRUE, Boolean.FALSE);
+
+ testProtocol.deserialize(null, mockInputStream);
+
+ verify(mockInputStream, times(3)).readObject();
+ }
+} \ No newline at end of file
diff --git a/src/test/java/protocols/implementations/VSPingPongProtocolTest.java b/src/test/java/protocols/implementations/VSPingPongProtocolTest.java
new file mode 100644
index 0000000..9735a01
--- /dev/null
+++ b/src/test/java/protocols/implementations/VSPingPongProtocolTest.java
@@ -0,0 +1,262 @@
+package protocols.implementations;
+
+import core.VSInternalProcess;
+import core.VSMessage;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import prefs.VSPrefs;
+import simulator.VSSimulatorVisualization;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+
+/**
+ * Unit tests for VSPingPongProtocol.
+ */
+class VSPingPongProtocolTest {
+
+ @Mock
+ private VSInternalProcess mockProcess;
+
+ @Mock
+ private VSSimulatorVisualization mockCanvas;
+
+ @Mock
+ private VSPrefs mockPrefs;
+
+ private VSPingPongProtocol protocol;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ protocol = new VSPingPongProtocol();
+ protocol.process = mockProcess;
+ protocol.prefs = mockPrefs;
+
+ // Setup mock chain
+ when(mockProcess.getSimulatorCanvas()).thenReturn(mockCanvas);
+ when(mockPrefs.getString(anyString())).thenReturn("TestString");
+ }
+
+ @Test
+ void testConstructor() {
+ VSPingPongProtocol newProtocol = new VSPingPongProtocol();
+ assertFalse(newProtocol.hasOnServerStart()); // Should use client start
+ assertNotNull(newProtocol.getClassname());
+ assertTrue(newProtocol.getClassname().contains("VSPingPongProtocol"));
+ }
+
+ @Test
+ void testClientInit() {
+ // Should do nothing but not throw exception
+ assertDoesNotThrow(() -> protocol.onClientInit());
+ }
+
+ @Test
+ void testServerInit() {
+ // Should do nothing but not throw exception
+ assertDoesNotThrow(() -> protocol.onServerInit());
+ }
+
+ @Test
+ void testClientReset() {
+ // First send some messages to increment counter
+ protocol.isClient(true);
+ protocol.onClientStart();
+ protocol.onClientStart();
+
+ // Reset should clear counter
+ protocol.onClientReset();
+
+ // Verify counter was reset by checking next message
+ ArgumentCaptor<VSMessage> messageCaptor = ArgumentCaptor.forClass(VSMessage.class);
+ protocol.onClientStart();
+
+ verify(mockProcess, atLeast(1)).sendMessage(messageCaptor.capture());
+ VSMessage lastMessage = messageCaptor.getValue();
+ assertEquals(1, lastMessage.getInteger("counter"));
+ }
+
+ @Test
+ void testServerReset() {
+ // Set up server mode
+ protocol.isServer(true);
+ protocol.currentContextIsServer(true);
+
+ // Create a mock client message
+ VSMessage clientMessage = new VSMessage();
+ clientMessage.setBoolean("fromClient", true);
+ clientMessage.setInteger("counter", 1);
+
+ // Process some messages to increment counter
+ protocol.onServerRecv(clientMessage);
+ protocol.onServerRecv(clientMessage);
+
+ // Reset should clear counter
+ protocol.onServerReset();
+
+ // Verify counter was reset by checking next message
+ ArgumentCaptor<VSMessage> messageCaptor = ArgumentCaptor.forClass(VSMessage.class);
+ protocol.onServerRecv(clientMessage);
+
+ verify(mockProcess, atLeast(1)).sendMessage(messageCaptor.capture());
+ VSMessage lastMessage = messageCaptor.getValue();
+ assertEquals(1, lastMessage.getInteger("counter"));
+ }
+
+ @Test
+ void testClientStart() {
+ protocol.isClient(true);
+
+ ArgumentCaptor<VSMessage> messageCaptor = ArgumentCaptor.forClass(VSMessage.class);
+
+ protocol.onClientStart();
+
+ verify(mockProcess).sendMessage(messageCaptor.capture());
+
+ VSMessage sentMessage = messageCaptor.getValue();
+ assertTrue(sentMessage.getBoolean("fromClient"));
+ assertEquals(1, sentMessage.getInteger("counter"));
+
+ // Test counter increment
+ protocol.onClientStart();
+
+ verify(mockProcess, times(2)).sendMessage(messageCaptor.capture());
+ sentMessage = messageCaptor.getValue();
+ assertEquals(2, sentMessage.getInteger("counter"));
+ }
+
+ @Test
+ void testClientRecv() {
+ protocol.isClient(true);
+
+ // Create a valid server message
+ VSMessage serverMessage = new VSMessage();
+ serverMessage.setBoolean("fromServer", true);
+ serverMessage.setInteger("counter", 5);
+
+ ArgumentCaptor<VSMessage> messageCaptor = ArgumentCaptor.forClass(VSMessage.class);
+
+ protocol.onClientRecv(serverMessage);
+
+ verify(mockProcess).sendMessage(messageCaptor.capture());
+
+ VSMessage sentMessage = messageCaptor.getValue();
+ assertTrue(sentMessage.getBoolean("fromClient"));
+ assertEquals(1, sentMessage.getInteger("counter"));
+ }
+
+ @Test
+ void testClientRecvIgnoresNonServerMessage() {
+ protocol.isClient(true);
+
+ // Create an invalid message (not from server)
+ VSMessage invalidMessage = new VSMessage();
+ invalidMessage.setBoolean("fromServer", false);
+ invalidMessage.setInteger("counter", 5);
+
+ protocol.onClientRecv(invalidMessage);
+
+ // Should not send any message
+ verify(mockProcess, never()).sendMessage(any());
+ }
+
+ @Test
+ void testServerRecv() {
+ protocol.isServer(true);
+ protocol.currentContextIsServer(true);
+
+ // Create a valid client message
+ VSMessage clientMessage = new VSMessage();
+ clientMessage.setBoolean("fromClient", true);
+ clientMessage.setInteger("counter", 3);
+
+ ArgumentCaptor<VSMessage> messageCaptor = ArgumentCaptor.forClass(VSMessage.class);
+
+ protocol.onServerRecv(clientMessage);
+
+ verify(mockProcess).sendMessage(messageCaptor.capture());
+
+ VSMessage sentMessage = messageCaptor.getValue();
+ assertTrue(sentMessage.getBoolean("fromServer"));
+ assertEquals(1, sentMessage.getInteger("counter"));
+ }
+
+ @Test
+ void testServerRecvIgnoresNonClientMessage() {
+ protocol.isServer(true);
+ protocol.currentContextIsServer(true);
+
+ // Create an invalid message (not from client)
+ VSMessage invalidMessage = new VSMessage();
+ invalidMessage.setBoolean("fromClient", false);
+ invalidMessage.setInteger("counter", 5);
+
+ protocol.onServerRecv(invalidMessage);
+
+ // Should not send any message
+ verify(mockProcess, never()).sendMessage(any());
+ }
+
+ @Test
+ void testClientSchedule() {
+ // Should do nothing but not throw exception
+ assertDoesNotThrow(() -> protocol.onClientSchedule());
+ }
+
+ @Test
+ void testServerSchedule() {
+ // Should do nothing but not throw exception
+ assertDoesNotThrow(() -> protocol.onServerSchedule());
+ }
+
+ @Test
+ void testToString() {
+ String result = protocol.toString();
+
+ assertNotNull(result);
+ assertTrue(result.contains("New message afterwards"));
+ assertTrue(result.contains("TestString"));
+ }
+
+ @Test
+ void testPingPongInteraction() {
+ // Test a full ping-pong interaction
+ protocol.isClient(true);
+ protocol.isServer(true);
+
+ ArgumentCaptor<VSMessage> messageCaptor = ArgumentCaptor.forClass(VSMessage.class);
+
+ // Client starts the ping
+ protocol.currentContextIsServer(false);
+ protocol.onClientStart();
+
+ verify(mockProcess, times(1)).sendMessage(messageCaptor.capture());
+ VSMessage ping = messageCaptor.getValue();
+ assertTrue(ping.getBoolean("fromClient"));
+ assertEquals(1, ping.getInteger("counter"));
+
+ // Server receives ping and sends pong
+ protocol.currentContextIsServer(true);
+ protocol.onServerRecv(ping);
+
+ verify(mockProcess, times(2)).sendMessage(messageCaptor.capture());
+ VSMessage pong = messageCaptor.getValue();
+ assertTrue(pong.getBoolean("fromServer"));
+ assertEquals(1, pong.getInteger("counter"));
+
+ // Client receives pong and sends another ping
+ protocol.currentContextIsServer(false);
+ protocol.onClientRecv(pong);
+
+ verify(mockProcess, times(3)).sendMessage(messageCaptor.capture());
+ VSMessage ping2 = messageCaptor.getValue();
+ assertTrue(ping2.getBoolean("fromClient"));
+ assertEquals(2, ping2.getInteger("counter"));
+ }
+} \ No newline at end of file