Coverage for src/prosemark/adapters/fake_id_generator.py: 100%
13 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-09-24 18:08 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-09-24 18:08 +0000
1# Copyright (c) 2024 Prosemark Contributors
2# This software is licensed under the MIT License
4"""In-memory fake implementation of IdGenerator for testing."""
6from prosemark.domain.models import NodeId
7from prosemark.ports.id_generator import IdGenerator
10class FakeIdGenerator(IdGenerator):
11 """Deterministic fake implementation of IdGenerator for testing.
13 Provides predictable ID generation for testing purposes using a sequence
14 of predefined UUIDv7 values. This enables deterministic test behavior
15 while maintaining the same interface contract as production implementations.
17 The generator cycles through a predefined list of valid UUIDv7 identifiers,
18 allowing tests to predict what IDs will be generated and assert on specific
19 values.
21 Examples:
22 >>> generator = FakeIdGenerator()
23 >>> node_id1 = generator.new()
24 >>> node_id2 = generator.new()
25 >>> str(node_id1)
26 '0192f0c1-0000-7000-8000-000000000001'
27 >>> str(node_id2)
28 '0192f0c1-0000-7000-8000-000000000002'
30 >>> # Custom sequence
31 >>> custom_ids = ['0192f0c1-1111-7000-8000-000000000001']
32 >>> generator = FakeIdGenerator(custom_ids)
33 >>> str(generator.new())
34 '0192f0c1-1111-7000-8000-000000000001'
36 """
38 def __init__(self, ids: list[str] | None = None) -> None:
39 """Initialize fake generator with predefined ID sequence.
41 Args:
42 ids: Optional list of UUIDv7 strings to use as the sequence.
43 If None, uses a default sequence of test IDs.
45 """
46 if ids is None: # pragma: no cover
47 # Default sequence of valid UUIDv7 test identifiers
48 ids = [
49 '0192f0c1-0000-7000-8000-000000000001',
50 '0192f0c1-0000-7000-8000-000000000002',
51 '0192f0c1-0000-7000-8000-000000000003',
52 '0192f0c1-0000-7000-8000-000000000004',
53 '0192f0c1-0000-7000-8000-000000000005',
54 '0192f0c1-0000-7000-8000-000000000006',
55 '0192f0c1-0000-7000-8000-000000000007',
56 '0192f0c1-0000-7000-8000-000000000008',
57 '0192f0c1-0000-7000-8000-000000000009',
58 '0192f0c1-0000-7000-8000-000000000010',
59 ]
61 self._ids = ids
62 self._current_index = 0
64 def new(self) -> NodeId:
65 """Generate the next NodeId in the sequence.
67 Returns:
68 The next NodeId from the predefined sequence
70 Raises:
71 IndexError: If all IDs in the sequence have been used
73 """
74 if self._current_index >= len(self._ids):
75 msg = 'All predefined IDs have been used' # pragma: no cover
76 raise IndexError(msg) # pragma: no cover
78 id_string = self._ids[self._current_index]
79 self._current_index += 1
80 return NodeId(id_string)
82 def reset(self) -> None: # pragma: no cover
83 """Reset the generator to start from the beginning of the sequence.
85 Useful for resetting state between test cases.
87 """
88 self._current_index = 0
90 def remaining_count(self) -> int: # pragma: no cover
91 """Get the number of IDs remaining in the sequence.
93 Returns:
94 Number of IDs that can still be generated
96 """
97 return len(self._ids) - self._current_index
99 def generated_count(self) -> int:
100 """Get the number of IDs that have been generated.
102 Returns:
103 Number of IDs that have been generated from this generator
105 """
106 return self._current_index
108 def peek_next(self) -> str: # pragma: no cover
109 """Peek at the next ID without consuming it.
111 Returns:
112 The next ID string that would be generated
114 Raises:
115 IndexError: If no more IDs are available
117 """
118 if self._current_index >= len(self._ids):
119 msg = 'No more IDs available'
120 raise IndexError(msg) # pragma: no cover
122 return self._ids[self._current_index]