/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ package com.github.copilot.sdk; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.jupiter.api.Test; import com.github.copilot.sdk.events.AssistantMessageEvent; import com.github.copilot.sdk.events.SessionIdleEvent; import com.github.copilot.sdk.json.MessageOptions; /** * Verifies the documented contract that {@code timeoutMs <= 0} means "no * timeout" in {@link CopilotSession#sendAndWait(MessageOptions, long)}. */ public class ZeroTimeoutContractTest { @SuppressWarnings("unchecked") @Test void sendAndWaitWithZeroTimeoutShouldNotTimeOut() throws Exception { // Build a session via reflection (package-private constructor) var ctor = CopilotSession.class.getDeclaredConstructor( String.class, JsonRpcClient.class, String.class); ctor.setAccessible(true); var mockRpc = mock(JsonRpcClient.class); when(mockRpc.invoke(any(), any(), any())) .thenReturn(new CompletableFuture<>()); var session = ctor.newInstance("zero-timeout-test", mockRpc, null); // Per the Javadoc: timeoutMs of 0 means "no timeout". // The future should NOT complete with TimeoutException. CompletableFuture result = session.sendAndWait(new MessageOptions().setPrompt("test"), 0); // Give the scheduler a chance to fire if it was (incorrectly) scheduled Thread.sleep(200); // The future should still be pending — not timed out assertFalse(result.isDone(), "Future should not be done; timeoutMs=0 means no timeout per Javadoc"); } }