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());
+ }
+}