Skip to main content

ps_uuid/methods/
set_version.rs

1use crate::UUID;
2
3impl UUID {
4    pub const fn set_version(&mut self, version: u8) {
5        self.bytes[6] &= 0x0F;
6        self.bytes[6] |= version << 4;
7
8        self.set_variant(crate::Variant::OSF);
9    }
10}
11
12#[cfg(test)]
13mod tests {
14    use super::UUID;
15
16    // Helper function to create a UUID with known bytes for testing
17    const fn create_test_uuid(bytes: [u8; 16]) -> UUID {
18        UUID { bytes }
19    }
20
21    // Helper function to check if a UUID has the OSF variant (10xx_xxxx in byte 8)
22    const fn has_osf_variant(uuid: &UUID) -> bool {
23        let byte8 = uuid.bytes[8];
24        (byte8 & 0b1100_0000) == 0b1000_0000
25    }
26
27    #[test]
28    fn test_set_valid_version() {
29        // Test setting versions 1–5 (common UUID versions)
30        let original_bytes = [
31            0x12, 0x34, 0x56, 0x78, // time_low
32            0x9A, 0xBC, // time_mid
33            0xDE, 0xF0, // time_hi_and_version, clock_seq_hi_and_reserved
34            0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // node
35        ];
36        let mut uuid = create_test_uuid(original_bytes);
37
38        for version in 1..=5 {
39            uuid.set_version(version);
40            // Check version is set correctly using version()
41            assert_eq!(
42                uuid.get_version(),
43                Some(version),
44                "Version should be set to {version}"
45            );
46            // Check byte 6: upper 4 bits = version, lower 4 bits preserved (0xE from 0xDE)
47            assert_eq!(
48                uuid.bytes[6],
49                (version << 4) | (original_bytes[6] & 0x0F),
50                "Byte 6 incorrect for version {version}"
51            );
52            // Verify OSF variant
53            assert!(
54                has_osf_variant(&uuid),
55                "OSF variant not set for version {version}"
56            );
57            // Check other bytes are unchanged
58            for (i, _) in original_bytes.iter().enumerate() {
59                if i != 6 && i != 8 {
60                    assert_eq!(
61                        uuid.bytes[i], original_bytes[i],
62                        "Byte {i} changed unexpectedly for version {version}"
63                    );
64                }
65            }
66        }
67    }
68
69    #[test]
70    fn test_set_version_zero() {
71        // Test setting version 0 (valid but uncommon)
72        let original_bytes = [0xFF; 16];
73        let mut uuid = create_test_uuid(original_bytes);
74
75        uuid.set_version(0);
76
77        assert_eq!(uuid.get_version(), Some(0), "Version should be set to 0");
78        assert_eq!(
79            uuid.bytes[6],
80            original_bytes[6] & 0x0F,
81            "Byte 6 should preserve lower bits with version 0"
82        );
83        assert!(has_osf_variant(&uuid), "OSF variant not set for version 0");
84        // Check other bytes unchanged except bytes 6 and 8
85        for (i, _) in original_bytes.iter().enumerate() {
86            if i != 6 && i != 8 {
87                assert_eq!(
88                    uuid.bytes[i], original_bytes[i],
89                    "Byte {i} changed unexpectedly"
90                );
91            }
92        }
93    }
94
95    #[test]
96    fn test_set_max_version() {
97        // Test setting version 15 (maximum possible value)
98        let original_bytes = [0x00; 16];
99        let mut uuid = create_test_uuid(original_bytes);
100
101        uuid.set_version(15);
102
103        assert_eq!(uuid.get_version(), Some(15), "Version should be set to 15");
104        assert_eq!(uuid.bytes[6], 0xF0, "Byte 6 should be 0xF0 for version 15");
105        assert!(has_osf_variant(&uuid), "OSF variant not set for version 15");
106        // Check other bytes unchanged except bytes 6 and 8
107        for (i, _) in original_bytes.iter().enumerate() {
108            if i != 6 && i != 8 {
109                assert_eq!(
110                    uuid.bytes[i], original_bytes[i],
111                    "Byte {i} changed unexpectedly"
112                );
113            }
114        }
115    }
116
117    #[test]
118    fn test_preserve_lower_nibble_byte6() {
119        // Test that lower 4 bits of byte 6 are preserved
120        let original_bytes = [
121            0x12, 0x34, 0x56, 0x78, // time_low
122            0x9A, 0xBC, // time_mid
123            0x5F, 0xFF, // time_hi_and_version (0x5F), clock_seq
124            0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // node
125        ];
126        let mut uuid = create_test_uuid(original_bytes);
127
128        uuid.set_version(3);
129
130        assert_eq!(uuid.get_version(), Some(3), "Version should be set to 3");
131        assert_eq!(
132            uuid.bytes[6], 0x3F,
133            "Byte 6 should have version 3 (0x3) in upper nibble and preserve 0xF in lower nibble"
134        );
135        assert!(has_osf_variant(&uuid), "OSF variant not set");
136    }
137
138    #[test]
139    fn test_idempotence() {
140        // Test that calling set_version multiple times yields consistent results
141        let original_bytes = [0xAA; 16];
142        let mut uuid = create_test_uuid(original_bytes);
143
144        uuid.set_version(1);
145
146        let after_first = uuid.bytes;
147
148        uuid.set_version(1);
149
150        assert_eq!(
151            uuid.bytes, after_first,
152            "Repeated calls with same version should be idempotent"
153        );
154        assert_eq!(uuid.get_version(), Some(1), "Version should remain 1");
155
156        uuid.set_version(2);
157
158        assert_eq!(uuid.get_version(), Some(2), "Version should change to 2");
159        assert!(has_osf_variant(&uuid), "OSF variant should persist");
160    }
161
162    #[test]
163    fn test_version_change_preserves_other_fields() {
164        // Test changing version preserves all fields except version and variant
165        let original_bytes = [
166            0x11, 0x22, 0x33, 0x44, // time_low
167            0x55, 0x66, // time_mid
168            0x7A, 0x88, // time_hi_and_version (0x7A), clock_seq
169            0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, // node
170        ];
171        let mut uuid = create_test_uuid(original_bytes);
172
173        uuid.set_version(4);
174
175        assert_eq!(uuid.get_version(), Some(4), "Version should be set to 4");
176        // Check all bytes except 6 (version) and 8 (variant)
177        let unchanged_indices = [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15];
178        for i in &unchanged_indices {
179            assert_eq!(
180                uuid.bytes[*i], original_bytes[*i],
181                "Byte {i} should remain unchanged"
182            );
183        }
184        // Check byte 6 preserves lower nibble (0xA from 0x7A)
185        assert_eq!(uuid.bytes[6], 0x4A, "Byte 6 should be 0x4A");
186        assert!(has_osf_variant(&uuid), "OSF variant not set");
187    }
188
189    #[test]
190    fn test_version_after_variant_change() {
191        // Test that setting version after variant change still works
192        let original_bytes = [0x00; 16];
193        let mut uuid = create_test_uuid(original_bytes);
194
195        uuid.set_version(5);
196        uuid.set_version(3);
197
198        assert_eq!(
199            uuid.get_version(),
200            Some(3),
201            "Version should be updated to 3"
202        );
203        assert!(has_osf_variant(&uuid), "OSF variant should be set");
204        assert_eq!(
205            uuid.bytes[6], 0x30,
206            "Byte 6 should reflect version 3 with zero lower nibble"
207        );
208    }
209}