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

1# Copyright (c) 2024 Prosemark Contributors 

2# This software is licensed under the MIT License 

3 

4"""In-memory fake implementation of IdGenerator for testing.""" 

5 

6from prosemark.domain.models import NodeId 

7from prosemark.ports.id_generator import IdGenerator 

8 

9 

10class FakeIdGenerator(IdGenerator): 

11 """Deterministic fake implementation of IdGenerator for testing. 

12 

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. 

16 

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. 

20 

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' 

29 

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' 

35 

36 """ 

37 

38 def __init__(self, ids: list[str] | None = None) -> None: 

39 """Initialize fake generator with predefined ID sequence. 

40 

41 Args: 

42 ids: Optional list of UUIDv7 strings to use as the sequence. 

43 If None, uses a default sequence of test IDs. 

44 

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 ] 

60 

61 self._ids = ids 

62 self._current_index = 0 

63 

64 def new(self) -> NodeId: 

65 """Generate the next NodeId in the sequence. 

66 

67 Returns: 

68 The next NodeId from the predefined sequence 

69 

70 Raises: 

71 IndexError: If all IDs in the sequence have been used 

72 

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 

77 

78 id_string = self._ids[self._current_index] 

79 self._current_index += 1 

80 return NodeId(id_string) 

81 

82 def reset(self) -> None: # pragma: no cover 

83 """Reset the generator to start from the beginning of the sequence. 

84 

85 Useful for resetting state between test cases. 

86 

87 """ 

88 self._current_index = 0 

89 

90 def remaining_count(self) -> int: # pragma: no cover 

91 """Get the number of IDs remaining in the sequence. 

92 

93 Returns: 

94 Number of IDs that can still be generated 

95 

96 """ 

97 return len(self._ids) - self._current_index 

98 

99 def generated_count(self) -> int: 

100 """Get the number of IDs that have been generated. 

101 

102 Returns: 

103 Number of IDs that have been generated from this generator 

104 

105 """ 

106 return self._current_index 

107 

108 def peek_next(self) -> str: # pragma: no cover 

109 """Peek at the next ID without consuming it. 

110 

111 Returns: 

112 The next ID string that would be generated 

113 

114 Raises: 

115 IndexError: If no more IDs are available 

116 

117 """ 

118 if self._current_index >= len(self._ids): 

119 msg = 'No more IDs available' 

120 raise IndexError(msg) # pragma: no cover 

121 

122 return self._ids[self._current_index]