|
| 1 | +package com.thealgorithms.bitmanipulation; |
| 2 | + |
| 3 | +import static org.junit.jupiter.api.Assertions.assertEquals; |
| 4 | + |
| 5 | +import java.util.Random; |
| 6 | +import org.junit.jupiter.api.DisplayName; |
| 7 | +import org.junit.jupiter.api.Test; |
| 8 | + |
| 9 | +/** |
| 10 | + * Unit tests for CountBitsFlip. |
| 11 | + * Covers: |
| 12 | + * - simple examples |
| 13 | + * - zeros and identical values |
| 14 | + * - negative numbers and two's complement edge cases |
| 15 | + * - Long.MIN_VALUE / Long.MAX_VALUE |
| 16 | + * - randomized consistency checks between two implementations |
| 17 | + */ |
| 18 | +@DisplayName("CountBitsFlip Tests") |
| 19 | +class CountBitsFlipTest { |
| 20 | + |
| 21 | + @Test |
| 22 | + @DisplayName("Example: A=10, B=20 => 4 bits") |
| 23 | + void exampleTenTwenty() { |
| 24 | + long a = 10L; |
| 25 | + long b = 20L; |
| 26 | + long expected = 4L; |
| 27 | + assertEquals(expected, CountBitsFlip.countBitsFlip(a, b), "Brian Kernighan implementation should return 4"); |
| 28 | + assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b), "Long.bitCount implementation should return 4"); |
| 29 | + } |
| 30 | + |
| 31 | + @Test |
| 32 | + @DisplayName("Identical values => 0 bits") |
| 33 | + void identicalValues() { |
| 34 | + long a = 123456789L; |
| 35 | + long b = 123456789L; |
| 36 | + long expected = 0L; |
| 37 | + assertEquals(expected, CountBitsFlip.countBitsFlip(a, b)); |
| 38 | + assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b)); |
| 39 | + } |
| 40 | + |
| 41 | + @Test |
| 42 | + @DisplayName("Both zeros => 0 bits") |
| 43 | + void bothZeros() { |
| 44 | + assertEquals(0L, CountBitsFlip.countBitsFlip(0L, 0L)); |
| 45 | + assertEquals(0L, CountBitsFlip.countBitsFlipAlternative(0L, 0L)); |
| 46 | + } |
| 47 | + |
| 48 | + @Test |
| 49 | + @DisplayName("Small example: A=15 (1111), B=8 (1000) => 3 bits") |
| 50 | + void smallExample() { |
| 51 | + long a = 15L; // 1111 |
| 52 | + long b = 8L; // 1000 |
| 53 | + long expected = 3L; // differs in three low bits |
| 54 | + assertEquals(expected, CountBitsFlip.countBitsFlip(a, b)); |
| 55 | + assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b)); |
| 56 | + } |
| 57 | + |
| 58 | + @Test |
| 59 | + @DisplayName("Negative values: -1 vs 0 => 64 bits (two's complement all ones)") |
| 60 | + void negativeVsZero() { |
| 61 | + long a = -1L; |
| 62 | + long b = 0L; |
| 63 | + long expected = 64L; // all 64 bits differ |
| 64 | + assertEquals(expected, CountBitsFlip.countBitsFlip(a, b)); |
| 65 | + assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b)); |
| 66 | + } |
| 67 | + |
| 68 | + @Test |
| 69 | + @DisplayName("Long.MIN_VALUE vs Long.MAX_VALUE => 64 bits") |
| 70 | + void minMaxLongs() { |
| 71 | + long a = Long.MIN_VALUE; |
| 72 | + long b = Long.MAX_VALUE; |
| 73 | + long expected = 64L; // MAX ^ MIN yields all ones on 64-bit long |
| 74 | + assertEquals(expected, CountBitsFlip.countBitsFlip(a, b)); |
| 75 | + assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b)); |
| 76 | + } |
| 77 | + |
| 78 | + @Test |
| 79 | + @DisplayName("Randomized consistency: both implementations agree across many pairs") |
| 80 | + void randomizedConsistency() { |
| 81 | + final int iterations = 1000; |
| 82 | + final Random rnd = new Random(12345L); // deterministic seed for reproducibility |
| 83 | + |
| 84 | + for (int i = 0; i < iterations; i++) { |
| 85 | + long a = rnd.nextLong(); |
| 86 | + long b = rnd.nextLong(); |
| 87 | + |
| 88 | + long res1 = CountBitsFlip.countBitsFlip(a, b); |
| 89 | + long res2 = CountBitsFlip.countBitsFlipAlternative(a, b); |
| 90 | + |
| 91 | + assertEquals(res2, res1, () -> String.format("Mismatch for a=%d, b=%d: impl1=%d, impl2=%d", a, b, res1, res2)); |
| 92 | + } |
| 93 | + } |
| 94 | +} |
0 commit comments