001package daikon.test; 002 003import static java.util.logging.Level.INFO; 004import static org.junit.Assert.assertEquals; 005 006import daikon.FileIO; 007import daikon.ModBitTracker; 008import daikon.ValueTuple; 009import java.util.BitSet; 010import java.util.Random; 011import org.junit.BeforeClass; 012import org.junit.Test; 013 014public class ModBitTrackerTest { 015 016 // Plan: 017 // Create many different variables. Give them a skewed distribution of 018 // random modbits so that it takes them a while to separate. In the end, 019 // give them modbits so that they are all separated. See if the results 020 // are as they should be. 021 022 // I should probably add some tests that test arguments other than 1 for 023 // the "count" argument to ModBitTracker.add(). 024 025 /** Random seed */ 026 private Random r = new Random(20031014L); 027 028 /** prepare for tests */ 029 @BeforeClass 030 public static void setUpClass() { 031 daikon.LogHelper.setupLogs(INFO); 032 FileIO.new_decl_format = true; 033 } 034 035 private ModBitTracker makeModBitTracker(BitSet[] bitsets) { 036 int numvars = bitsets.length; 037 int numsamples = bitsets[0].size(); 038 039 ModBitTracker result = new ModBitTracker(numvars); 040 041 Object[] vals = new Object[numvars]; 042 int[] mods = new int[numvars]; 043 // We'll reuse this ValueTuple throughout, side-effecting its mods array. 044 ValueTuple vt = ValueTuple.makeUninterned(vals, mods); 045 for (int sampleno = 0; sampleno < numsamples; sampleno++) { 046 for (int var = 0; var < numvars; var++) { 047 mods[var] = booleanToModBit(bitsets[var].get(sampleno)); 048 } 049 result.add(vt, 1); 050 } 051 return result; 052 } 053 054 private void checkModBitTracker(ModBitTracker mbt, BitSet[] bitsets) { 055 int numvars = bitsets.length; 056 int numsamples = bitsets[0].size(); 057 058 assertEquals(numvars, mbt.num_vars()); 059 assertEquals(numsamples, mbt.num_samples()); 060 061 for (int i = 0; i < numvars; i++) { 062 assertEquals(mbt.get(i), bitsets[i]); 063 } 064 } 065 066 private int booleanToModBit(boolean b) { 067 return (b ? ValueTuple.MODIFIED : ValueTuple.MISSING_NONSENSICAL); 068 } 069 070 private boolean randomModBoolean(int varno, int sampleno) { 071 boolean unusual = (r.nextInt(100) == 0); 072 boolean result; 073 if (varno % 2 == 0) { 074 result = (varno % 2 == 0); 075 } else { 076 result = ((varno + sampleno) % 2 == 0); 077 } 078 if (unusual) { 079 result = !result; 080 } 081 return result; 082 } 083 084 // Make numvars different unique random BitSets, each of size 085 // numsamples+numvars. Then add duplicate_factor more BitSets (e.g., if 086 // duplicate_factor is 1, then double the number of BitSets), where each 087 // of the additional ones is a duplicate of one of the unique ones. 088 089 BitSet[] makeBitSets(int numvars, int numsamples, double duplicate_factor) { 090 int totalvars = (int) (numvars * (1 + duplicate_factor)); 091 BitSet[] result = new BitSet[totalvars]; 092 for (int var = 0; var < numvars; var++) { 093 BitSet bs = new BitSet(numsamples + numvars); 094 for (int sample = 0; sample < numsamples; sample++) { 095 bs.set(sample, randomModBoolean(var, sample)); 096 } 097 // add samples that make all the variables unique 098 bs.set(numsamples + numvars - 1, false); 099 bs.set(numsamples + var, true); 100 result[var] = bs; 101 } 102 // Add duplicate BitSets. 103 for (int var = numvars; var < totalvars; var++) { 104 result[var] = (BitSet) result[r.nextInt(numvars)].clone(); 105 } 106 return result; 107 } 108 109 public void oneModBitTrackerTest(int vars, int samples, double duplicate_factor) { 110 BitSet[] bitsets = makeBitSets(vars, samples, duplicate_factor); 111 ModBitTracker mbt = makeModBitTracker(bitsets); 112 checkModBitTracker(mbt, bitsets); 113 assertEquals(vars, mbt.num_sets()); 114 } 115 116 @Test 117 public void testModBitTracker() { 118 oneModBitTrackerTest(1, 2, 0.0); 119 oneModBitTrackerTest(2, 2, 0.0); 120 oneModBitTrackerTest(5, 10, 0.0); 121 oneModBitTrackerTest(100, 1000, 5.0); 122 } 123}