@@ -42,3 +42,108 @@ impl Mutator for BitFlipMutator {
4242 Some ( value ^ ( 1 << bit_pos) )
4343 }
4444}
45+
46+ #[ cfg( test) ]
47+ mod tests {
48+ use super :: * ;
49+ use crate :: generator:: GenerationSource ;
50+ use rand:: SeedableRng ;
51+ use rand_chacha:: ChaCha8Rng ;
52+
53+ #[ test]
54+ fn test_bitflip_name ( ) {
55+ let mutator = BitFlipMutator ;
56+ assert_eq ! ( mutator. name( ) , "bitflip" ) ;
57+ }
58+
59+ #[ test]
60+ fn test_bitflip_int_always_mutates_at_rate_1 ( ) {
61+ let mutator = BitFlipMutator ;
62+ let mut rng = ChaCha8Rng :: seed_from_u64 ( 42 ) ;
63+ let mut source = GenerationSource :: Rand ( & mut rng) ;
64+
65+ let original = 0b1010_1010 ;
66+ let result = mutator. mutate_int ( original, & mut source, 1.0 ) ;
67+
68+ assert ! ( result. is_some( ) ) ;
69+ let mutated = result. unwrap ( ) ;
70+ assert_ne ! ( mutated, original) ;
71+
72+ // verify exactly one bit flipped
73+ let diff = original ^ mutated;
74+ assert_eq ! ( diff. count_ones( ) , 1 ) ;
75+ }
76+
77+ #[ test]
78+ fn test_bitflip_int_never_mutates_at_rate_0 ( ) {
79+ let mutator = BitFlipMutator ;
80+ let mut rng = ChaCha8Rng :: seed_from_u64 ( 42 ) ;
81+ let mut source = GenerationSource :: Rand ( & mut rng) ;
82+
83+ let result = mutator. mutate_int ( 100 , & mut source, 0.0 ) ;
84+ assert ! ( result. is_none( ) ) ;
85+ }
86+
87+ #[ test]
88+ fn test_bitflip_long_always_mutates_at_rate_1 ( ) {
89+ let mutator = BitFlipMutator ;
90+ let mut rng = ChaCha8Rng :: seed_from_u64 ( 42 ) ;
91+ let mut source = GenerationSource :: Rand ( & mut rng) ;
92+
93+ let original = 0x1234_5678_9ABC_DEF0_i64 ;
94+ let result = mutator. mutate_long ( original, & mut source, 1.0 ) ;
95+
96+ assert ! ( result. is_some( ) ) ;
97+ let mutated = result. unwrap ( ) ;
98+ assert_ne ! ( mutated, original) ;
99+
100+ // verify exactly one bit flipped
101+ let diff = original ^ mutated;
102+ assert_eq ! ( diff. count_ones( ) , 1 ) ;
103+ }
104+
105+ #[ test]
106+ fn test_bitflip_long_never_mutates_at_rate_0 ( ) {
107+ let mutator = BitFlipMutator ;
108+ let mut rng = ChaCha8Rng :: seed_from_u64 ( 42 ) ;
109+ let mut source = GenerationSource :: Rand ( & mut rng) ;
110+
111+ let result = mutator. mutate_long ( 1000 , & mut source, 0.0 ) ;
112+ assert ! ( result. is_none( ) ) ;
113+ }
114+
115+ #[ test]
116+ fn test_bitflip_int_zero ( ) {
117+ let mutator = BitFlipMutator ;
118+ let mut rng = ChaCha8Rng :: seed_from_u64 ( 42 ) ;
119+ let mut source = GenerationSource :: Rand ( & mut rng) ;
120+
121+ let result = mutator. mutate_int ( 0 , & mut source, 1.0 ) ;
122+ assert ! ( result. is_some( ) ) ;
123+
124+ // flipping any bit in 0 gives a power of 2
125+ let mutated = result. unwrap ( ) ;
126+ assert_ne ! ( mutated, 0 ) ;
127+ assert_eq ! ( mutated. count_ones( ) , 1 ) ;
128+ }
129+
130+ #[ test]
131+ fn test_bitflip_produces_different_results ( ) {
132+ let mutator = BitFlipMutator ;
133+ let mut rng = ChaCha8Rng :: seed_from_u64 ( 42 ) ;
134+ let mut source = GenerationSource :: Rand ( & mut rng) ;
135+
136+ let value = 0xFF00 ;
137+ let mut results = std:: collections:: HashSet :: new ( ) ;
138+
139+ // collect multiple mutations
140+ for _ in 0 ..20 {
141+ if let Some ( mutated) = mutator. mutate_int ( value, & mut source, 1.0 ) {
142+ results. insert ( mutated) ;
143+ }
144+ }
145+
146+ // should produce multiple different results
147+ assert ! ( results. len( ) > 1 ) ;
148+ }
149+ }
0 commit comments