1+ import uuid
2+ from unittest .mock import patch
3+
4+ import pytest
5+
6+ from a2a .server .id_generator import IDGeneratorContext , IDGenerator , UUIDGenerator
7+
8+
9+ class TestIDGeneratorContext :
10+ """Tests for IDGeneratorContext."""
11+
12+ def test_context_creation_with_all_fields (self ):
13+ """Test creating context with all fields populated."""
14+ context = IDGeneratorContext (task_id = "task_123" , context_id = "context_456" )
15+ assert context .task_id == "task_123"
16+ assert context .context_id == "context_456"
17+
18+ def test_context_creation_with_defaults (self ):
19+ """Test creating context with default None values."""
20+ context = IDGeneratorContext ()
21+ assert context .task_id is None
22+ assert context .context_id is None
23+
24+ def test_context_creation_with_partial_fields (self ):
25+ """Test creating context with only some fields populated."""
26+ context = IDGeneratorContext (task_id = "task_123" )
27+ assert context .task_id == "task_123"
28+ assert context .context_id is None
29+
30+ def test_context_mutability (self ):
31+ """Test that context fields can be updated (Pydantic models are mutable by default)."""
32+ context = IDGeneratorContext (task_id = "task_123" )
33+ context .task_id = "task_456"
34+ assert context .task_id == "task_456"
35+
36+ def test_context_validation (self ):
37+ """Test that context validates field types."""
38+ context = IDGeneratorContext (task_id = "valid_string" )
39+ assert isinstance (context .task_id , str )
40+
41+
42+ class TestIDGenerator :
43+ """Tests for IDGenerator abstract base class."""
44+
45+ def test_cannot_instantiate_abstract_class (self ):
46+ """Test that IDGenerator cannot be instantiated directly."""
47+ with pytest .raises (TypeError ):
48+ IDGenerator () # noqa
49+
50+ def test_subclass_must_implement_generate (self ):
51+ """Test that subclasses must implement the generate method."""
52+
53+ class IncompleteGenerator (IDGenerator ): # noqa
54+ pass
55+
56+ with pytest .raises (TypeError ):
57+ IncompleteGenerator () # noqa
58+
59+ def test_valid_subclass_implementation (self ):
60+ """Test that a valid subclass can be instantiated."""
61+
62+ class ValidGenerator (IDGenerator ):
63+ def generate (self , context : IDGeneratorContext ) -> str :
64+ return "test_id"
65+
66+ generator = ValidGenerator ()
67+ assert generator .generate (IDGeneratorContext ()) == "test_id"
68+
69+
70+ class TestUUIDGenerator :
71+ """Tests for UUIDGenerator implementation."""
72+
73+ def test_generate_returns_string (self ):
74+ """Test that generate returns a string."""
75+ generator = UUIDGenerator ()
76+ context = IDGeneratorContext ()
77+ result = generator .generate (context )
78+ assert isinstance (result , str )
79+
80+ def test_generate_returns_valid_uuid (self ):
81+ """Test that generate returns a valid UUID format."""
82+ generator = UUIDGenerator ()
83+ context = IDGeneratorContext ()
84+ result = generator .generate (context )
85+
86+ # This should not raise an exception if result is a valid UUID
87+ uuid .UUID (result )
88+
89+ def test_generate_returns_uuid_version_4 (self ):
90+ """Test that generate returns a UUID version 4."""
91+ generator = UUIDGenerator ()
92+ context = IDGeneratorContext ()
93+ result = generator .generate (context )
94+
95+ parsed_uuid = uuid .UUID (result )
96+ assert parsed_uuid .version == 4
97+
98+ def test_generate_ignores_context (self ):
99+ """Test that generate ignores the context parameter."""
100+ generator = UUIDGenerator ()
101+ context1 = IDGeneratorContext (task_id = "task_1" , context_id = "context_1" )
102+ context2 = IDGeneratorContext (task_id = "task_2" , context_id = "context_2" )
103+
104+ result1 = generator .generate (context1 )
105+ result2 = generator .generate (context2 )
106+
107+ # Both should be valid UUIDs but different
108+ uuid .UUID (result1 )
109+ uuid .UUID (result2 )
110+ assert result1 != result2
111+
112+ def test_generate_produces_unique_ids (self ):
113+ """Test that multiple calls produce unique IDs."""
114+ generator = UUIDGenerator ()
115+ context = IDGeneratorContext ()
116+
117+ ids = [generator .generate (context ) for _ in range (100 )]
118+
119+ # All IDs should be unique
120+ assert len (ids ) == len (set (ids ))
121+
122+ def test_generate_with_empty_context (self ):
123+ """Test that generate works with an empty context."""
124+ generator = UUIDGenerator ()
125+ context = IDGeneratorContext ()
126+ result = generator .generate (context )
127+
128+ assert isinstance (result , str )
129+ uuid .UUID (result )
130+
131+ def test_generate_with_populated_context (self ):
132+ """Test that generate works with a populated context."""
133+ generator = UUIDGenerator ()
134+ context = IDGeneratorContext (task_id = "task_123" , context_id = "context_456" )
135+ result = generator .generate (context )
136+
137+ assert isinstance (result , str )
138+ uuid .UUID (result )
139+
140+ @patch ('uuid.uuid4' )
141+ def test_generate_calls_uuid4 (self , mock_uuid4 ):
142+ """Test that generate uses uuid.uuid4() internally."""
143+ mock_uuid = uuid .UUID ('12345678-1234-5678-1234-567812345678' )
144+ mock_uuid4 .return_value = mock_uuid
145+
146+ generator = UUIDGenerator ()
147+ context = IDGeneratorContext ()
148+ result = generator .generate (context )
149+
150+ mock_uuid4 .assert_called_once ()
151+ assert result == str (mock_uuid )
152+
153+ def test_generator_is_instance_of_id_generator (self ):
154+ """Test that UUIDGenerator is an instance of IDGenerator."""
155+ generator = UUIDGenerator ()
156+ assert isinstance (generator , IDGenerator )
157+
158+ def test_multiple_generators_produce_different_ids (self ):
159+ """Test that multiple generator instances produce different IDs."""
160+ generator1 = UUIDGenerator ()
161+ generator2 = UUIDGenerator ()
162+ context = IDGeneratorContext ()
163+
164+ result1 = generator1 .generate (context )
165+ result2 = generator2 .generate (context )
166+
167+ assert result1 != result2
0 commit comments