import java.util.Random; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class BitStringTest { private BitString bs1; private BitString bs1sc; private BitString bs1s; private BitString bs1cs; private BitString bs2; private BitString bs2s; private BitString bs2ss; private BitString bs3; private BitString bs3s; private BitString bs4; public BitStringTest() { } @Before public void setUp() { bs1 = new BitString("1100001111011010101000010110111001110001101110011001111010101010001101011011110111101011000100100010"); bs1s = new BitString("1100001111011010101000010110111001110001101110011001111010101010001101011011110111101011000100100011"); bs1sc = new BitString("0011110000100101010111101001000110001110010001100110000101010101110010100100001000010100111011011100"); bs1cs = new BitString("0011110000100101010111101001000110001110010001100110000101010101110010100100001000010100111011011110"); bs2 = new BitString("1100110100101000110101101101111111001100101010011111111011000000000100011010011110000011011010110110"); bs2s = new BitString("1100110100101000110101101101111111001100101010011111111011000000000100011010011110000011011010110111"); bs2ss = new BitString("1100110100101000110101101101111111001100101010011111111011000000000100011010011110000011011010111000"); bs3 = new BitString("1011100001100101100000010001010111001101111010010101001110110011100111000010110010111011100000010000"); bs3s = new BitString("1011100001100101100000010001010111001101111010010101001110110011100111000010110010111011100000010001"); bs4 = new BitString("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); } @Test public void testSuccessor() { BitString successor = bs1.successor(); assertEquals(bs1s, successor); assertSame(bs1, successor); assertEquals(bs2s, bs2.successor()); assertEquals(bs2ss, bs2.successor()); assertEquals(bs2ss, bs2s.successor()); assertEquals(bs3s, bs3.successor()); assertEquals(new BitString(100), bs4.successor()); for (int size = 1; size <= 16; ++size) { BitString start = new BitString(size); for (int number = 0; number < Math.pow(2, size); ++number) { StringBuilder expected = new StringBuilder(size); String binaryString = Integer.toBinaryString(number); // add leading 0's for (int i = 0; i < size - binaryString.length(); ++i) { expected.append("0"); } expected.append(binaryString); assertEquals(expected.toString(), start.toString()); assertEquals(expected.toString(), new BitString(expected.toString()).toString()); start.successor(); } } } @Test public void testDecimalToUnsigned() { for (int size = 1; size <= 16; ++size) { for (int number = 0; number <= Math.pow(2, size + 2); ++number) { String binaryString = Integer.toBinaryString(number); try { BitString bs = BitString.decimalToUnsigned(number, size); assertTrue("InsufficientNumberOfBitsException should have been thrown for n = " + number + ", size = " + size, binaryString.length() <= size); StringBuilder expected = new StringBuilder(size); // add leading 0's for (int i = 0; i < size - binaryString.length(); ++i) { expected.append("0"); } expected.append(binaryString); assertEquals(expected.toString(), bs.toString()); } catch (BitString.InsufficientNumberOfBitsException e) { assertFalse("InsufficientNumberOfBitsException should not have been thrown for n = " + number + ", size = " + size, binaryString.length() <= size); } } } } private void complementSubTest(BitString bs) { BitString clone = (BitString) bs.clone(); BitString comp = clone.complement(); assertSame(clone, comp); assertTrue("Size of complement must equal the size of the orginal. " + comp + " " + bs, comp.size() == bs.size()); for (int index = 0; index < comp.size(); ++index) { assertTrue("Complement must be differant in each index." + comp + " " + bs, comp.get(index) != bs.get(index)); } assertEquals("Complement should be its own inverse.", comp.complement(), bs); } @Test public void testComplementQuick() { complementSubTest(bs1); complementSubTest(bs2); complementSubTest(bs3); complementSubTest(bs4); BitString bs = new BitString(256); for (int index = 0; index < bs.size(); ++index) { complementSubTest(bs); bs.flip(index); } complementSubTest(bs); } @Test public void testComplementFull() { for (int size = 1; size <= 16; ++size) { BitString start = new BitString(size); for (int number = 0; number < Math.pow(2, size); ++number) { complementSubTest(start); } try { start.successor(); } catch (UnsupportedOperationException e) { throw new Error("Successor method is unsupported but is needed for complement test."); } } } public void twosComplementSubTest(BitString bs) { BitString clone = (BitString) bs.clone(); BitString comp = clone.twosComplement(); assertSame(clone, comp); BitString zero = new BitString(bs.size()); assertTrue("Size of two's complement must equal the size of the orginal. " + comp + " " + bs, comp.size() == bs.size()); try { assertEquals("Two's complement " + comp + " and orginal " + bs + " should sum to 0.", zero, comp.add(bs)); assertEquals("Two's complement " + comp + " and orginal " + bs + " should sum to 0.", zero, bs.add(comp)); } catch (UnsupportedOperationException ex) { throw new Error("Add method is unsupported but is needed for two's complement test."); } assertEquals("Two's complement should be its own inverse.", comp.twosComplement(), bs); } @Test public void testTwosComplementQuick() { assertEquals(bs1cs, bs1.twosComplement()); BitString bs = new BitString(256); for (int index = 0; index < bs.size(); ++index) { twosComplementSubTest(bs); bs.flip(index); } twosComplementSubTest(bs); } @Test public void testTwosComplementFull() { for (int size = 1; size <= 16; ++size) { BitString start = new BitString(size); for (int number = 0; number < Math.pow(2, size); ++number) { twosComplementSubTest(start); } try { start.successor(); } catch (UnsupportedOperationException e) { throw new Error("Successor method is unsupported but is needed for two's complement test."); } } } @Test public void testUnsignedValue() { for (int number = 0; number < (1 << 16) - 1; number++) { String binaryString = Integer.toBinaryString(number); assertEquals(number, new BitString(binaryString).unsignedValue()); } } @Test public void testSignedValue() { for (int number = 0; number < (1 << 16) - 1; number++) { String binaryString = Integer.toBinaryString(number); assertEquals(number, new BitString("0" + binaryString).signedValue()); assertEquals(-number, new BitString("1" + binaryString).signedValue()); } } @Test public void testOnesComplementValue() { for (int number = 1; number < (1 << 16) - 1; number++) { assertEquals(number, new BitString("0" + Integer.toBinaryString(number)).onesComplementValue()); assertEquals(-number, new BitString("1" + Integer.toBinaryString(number ^ Integer.MAX_VALUE)).onesComplementValue()); } } @Test public void testTwosComplementValue() { for (int number = 1; number < (1 << 16) - 1; number++) { assertEquals(number, new BitString("0" + Integer.toBinaryString(number)).twosComplementValue()); assertEquals(-number, new BitString("1" + Integer.toBinaryString(-number)).twosComplementValue()); } } @Test public void testAdd() { for (int a = 0; a < (1 << 8) - 1; a++) { for (int b = 0; b < (1 << 8) - 1; b++) { String sA = String.format("%8s", Integer.toBinaryString(a)).replace(' ', '0'); String sB = String.format("%8s", Integer.toBinaryString(b)).replace(' ', '0'); String sSum = String.format("%8s", Integer.toBinaryString(a + b)).replace(' ', '0'); sA = sA.substring(sA.length() - 8); sB = sB.substring(sB.length() - 8); sSum = sSum.substring(sSum.length() - 8); BitString bsa = new BitString(sA); BitString bsb = new BitString(sB); BitString sum = new BitString(sSum); BitString test = bsa.add(bsb); assertEquals(sum, test); assertEquals(new BitString(String.format("%8s", Integer.toBinaryString(a)).replace(' ', '0')), bsa); assertEquals(new BitString(String.format("%8s", Integer.toBinaryString(b)).replace(' ', '0')), bsb); assertEquals(sum, bsb.add(bsa)); } } } @Test public void testSubtract() { for (byte a = 0; a < Byte.MAX_VALUE; a++) { for (byte b = 0; b < Byte.MAX_VALUE; b++) { String sA = String.format("%8s", Integer.toBinaryString(a)).replace(' ', '0'); String sB = String.format("%8s", Integer.toBinaryString(b)).replace(' ', '0'); String sDiff = String.format("%8s", Integer.toBinaryString(a - b)).replace(' ', '0'); sA = sA.substring(sA.length() - 8); sB = sB.substring(sB.length() - 8); sDiff = sDiff.substring(sDiff.length() - 8); BitString bsa = new BitString(sA); BitString bsb = new BitString(sB); BitString diff = new BitString(sDiff); BitString test = bsa.subtract(bsb); assertEquals(diff, test); assertEquals(new BitString(String.format("%8s", Integer.toBinaryString(a)).replace(' ', '0')), bsa); assertEquals(new BitString(String.format("%8s", Integer.toBinaryString(b)).replace(' ', '0')), bsb); } } } @Test public void testLogicalAnd() { Random r = new Random(); for (byte index = 0; index < Byte.MAX_VALUE; index++) { StringBuilder setA = new StringBuilder(1000); StringBuilder setB = new StringBuilder(setA.capacity()); StringBuilder setC = new StringBuilder(setA.capacity()); for (int i = 0; i < setA.capacity(); i++) { boolean a = r.nextBoolean(); boolean b = r.nextBoolean(); boolean c = a && b; setA.append(a ? "1" : "0"); setB.append(b ? "1" : "0"); setC.append(c ? "1" : "0"); } BitString bsA = new BitString(setA.toString()); BitString bsB = new BitString(setB.toString()); BitString bsC = bsA.logicalAnd(bsB); assertEquals(setC.toString(), bsC.toString()); assertEquals(setA.toString(), bsA.toString()); assertEquals(setB.toString(), bsB.toString()); assertEquals(setC.toString(), bsB.logicalAnd(bsA).toString()); } try { new BitString(100).add(new BitString(101)); fail("BitSizeMismatchException should have been thrown"); } catch(BitString.BitSizeMismatchException e) { } } @Test public void testLogicalOr() { Random r = new Random(); for (byte index = 0; index < Byte.MAX_VALUE; index++) { StringBuilder setA = new StringBuilder(1000); StringBuilder setB = new StringBuilder(setA.capacity()); StringBuilder setC = new StringBuilder(setA.capacity()); for (int i = 0; i < setA.capacity(); i++) { boolean a = r.nextBoolean(); boolean b = r.nextBoolean(); boolean c = a || b; setA.append(a ? "1" : "0"); setB.append(b ? "1" : "0"); setC.append(c ? "1" : "0"); } BitString bsA = new BitString(setA.toString()); BitString bsB = new BitString(setB.toString()); BitString bsC = bsA.logicalOr(bsB); assertEquals(setC.toString(), bsC.toString()); assertEquals(setA.toString(), bsA.toString()); assertEquals(setB.toString(), bsB.toString()); assertEquals(setC.toString(), bsB.logicalOr(bsA).toString()); } try { new BitString(100).add(new BitString(101)); fail("BitSizeMismatchException should have been thrown"); } catch(BitString.BitSizeMismatchException e) { } } @Test public void testLeftShift() { for (short a = 0; a < Short.MAX_VALUE; a++) { for (int shift = -2; shift < 17; shift++) { String sA = String.format("%15s", Integer.toBinaryString(a)).replace(' ', '0'); String sB = String.format("%15s", Integer.toBinaryString(a << shift)).replace(' ', '0'); sA = sA.substring(sA.length() - 15); sB = sB.substring(sB.length() - 15); BitString bsa = new BitString(sA); BitString bsb = new BitString(sB); try { BitString test = bsa.leftShift(shift); if(shift < 0) fail("Exception should have been thrown"); assertEquals(bsb, test); assertSame(test, bsa); } catch (Exception e) { if(shift >= 0) fail("Exception " + e + " should not have been thrown."); } } } } @Test public void testSignExtension() { for (int a = (1 << 14); a < (1 << 16); a++) { for (int shift = -2; shift < 32; shift++) { String sA = String.format("%16s", Integer.toBinaryString(a)).replace(' ', '0'); StringBuilder sB = new StringBuilder(sA); for(int i = 0; i < shift; i++) { sB.insert(0, (short) a > 0 ? "0" : "1"); } BitString bsa = new BitString(sA); BitString bsb = new BitString(sB.toString()); try { BitString test = bsa.signExtension(shift); if(shift < 0) fail("Exception should have been thrown"); assertEquals(bsb, test); assertSame(test, bsa); } catch (Exception e) { if(shift >= 0) fail("Exception " + e + " should not have been thrown."); } } } } }