From 1da4049f4fedf7e106ee84600e6411d90fddfc09 Mon Sep 17 00:00:00 2001 From: Neo <544251790@qq.com> Date: Fri, 13 Mar 2026 03:07:02 +0800 Subject: [PATCH] test: add unit tests for DeviceCodeOAuthFlow Add DeviceCodeOAuthFlowTest with tests covering: - Construction with all fields - Null refreshUrl (optional field) - Empty scopes map - Null validation for required fields (deviceAuthorizationUrl, tokenUrl, scopes) - Record equality and hashCode Fixes #607 --- .../io/a2a/spec/DeviceCodeOAuthFlowTest.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 spec/src/test/java/io/a2a/spec/DeviceCodeOAuthFlowTest.java diff --git a/spec/src/test/java/io/a2a/spec/DeviceCodeOAuthFlowTest.java b/spec/src/test/java/io/a2a/spec/DeviceCodeOAuthFlowTest.java new file mode 100644 index 000000000..fffde8fa7 --- /dev/null +++ b/spec/src/test/java/io/a2a/spec/DeviceCodeOAuthFlowTest.java @@ -0,0 +1,81 @@ +package io.a2a.spec; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link DeviceCodeOAuthFlow}. + *

+ * Tests cover construction with valid parameters, null validation of required + * fields, and handling of the optional {@code refreshUrl} field. + * + * @see DeviceCodeOAuthFlow + */ +class DeviceCodeOAuthFlowTest { + + private static final String DEVICE_AUTH_URL = "https://auth.example.com/device/code"; + private static final String TOKEN_URL = "https://auth.example.com/token"; + private static final String REFRESH_URL = "https://auth.example.com/refresh"; + private static final Map SCOPES = Map.of("read", "Read access", "write", "Write access"); + + @Test + void testConstruction_withAllFields() { + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, SCOPES); + + assertEquals(DEVICE_AUTH_URL, flow.deviceAuthorizationUrl()); + assertEquals(TOKEN_URL, flow.tokenUrl()); + assertEquals(REFRESH_URL, flow.refreshUrl()); + assertEquals(SCOPES, flow.scopes()); + } + + @Test + void testConstruction_withNullRefreshUrl() { + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, null, SCOPES); + + assertEquals(DEVICE_AUTH_URL, flow.deviceAuthorizationUrl()); + assertEquals(TOKEN_URL, flow.tokenUrl()); + assertNull(flow.refreshUrl()); + assertEquals(SCOPES, flow.scopes()); + } + + @Test + void testConstruction_withEmptyScopes() { + DeviceCodeOAuthFlow flow = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, null, Map.of()); + + assertNotNull(flow.scopes()); + assertEquals(0, flow.scopes().size()); + } + + @Test + void testConstruction_nullDeviceAuthorizationUrl_throwsException() { + assertThrows(IllegalArgumentException.class, + () -> new DeviceCodeOAuthFlow(null, TOKEN_URL, REFRESH_URL, SCOPES)); + } + + @Test + void testConstruction_nullTokenUrl_throwsException() { + assertThrows(IllegalArgumentException.class, + () -> new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, null, REFRESH_URL, SCOPES)); + } + + @Test + void testConstruction_nullScopes_throwsException() { + assertThrows(IllegalArgumentException.class, + () -> new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, null)); + } + + @Test + void testEquality_sameValues() { + DeviceCodeOAuthFlow flow1 = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, SCOPES); + DeviceCodeOAuthFlow flow2 = new DeviceCodeOAuthFlow(DEVICE_AUTH_URL, TOKEN_URL, REFRESH_URL, SCOPES); + + assertEquals(flow1, flow2); + assertEquals(flow1.hashCode(), flow2.hashCode()); + } +}