bug fix: retrieve by full key returned empty set, now correct
[IRC.git] / Robust / src / Util / UnitTests / MultiViewMapTest.java
1 package Util.UnitTests;
2
3 import Util.*;
4
5 import java.util.Set;
6 import java.util.HashSet;
7 import java.util.BitSet;
8 import java.util.Map;
9 import java.util.HashMap;
10 import java.util.Random;
11 import java.lang.reflect.Array;
12
13
14 public class MultiViewMapTest {
15
16   private static JoinOpInteger joinOp;
17
18   private static Random random;
19
20   private static int numTests  = 0;
21   private static int numPassed = 0;
22
23   private static void p() { numTests++; numPassed++; System.out.print( "." ); }
24   private static void f() { numTests++; System.out.println( "!!!FAILED!!!" ); }
25
26   private static void verify( Map<MultiKey, Integer> expected, 
27                               Map<MultiKey, Integer> actual ) {
28     if( expected.equals( actual ) ) { 
29       p();
30     } else { 
31       f();
32       System.out.println( "expected = "+expected );
33       System.out.println( "actual   = "+actual );
34     }
35   }
36
37
38   public static void main(String[] args) {
39     
40     int randomSeed = 12345;
41     if( args.length > 0 ) {
42       randomSeed = Integer.parseInt( args[0] );
43     }
44     random = new Random( randomSeed );
45
46     joinOp = new JoinOpInteger();
47     
48     System.out.println("");
49     testBuilder();
50     System.out.println("");
51     testMap();
52     System.out.println("");
53     stressTest();
54     System.out.println("");
55     System.out.println(numPassed+"/"+numTests+" passed.");
56   }
57
58
59   public static void testBuilder() {
60     System.out.println( "Testing MultiViewMapBuilder..." );
61
62     MultiViewMapBuilder builder;
63
64     try {
65       builder = new MultiViewMapBuilder<Integer>( new Class[]{}, joinOp );
66       f();
67     } catch( IllegalArgumentException expected ) {
68       p();
69     } catch( Exception e ) {
70       f();
71     }
72
73     try {
74       builder =
75         new MultiViewMapBuilder<Integer>( new Class[] 
76                                           {Integer.class,
77                                            Boolean.class,
78                                            Integer.class,
79                                            String.class},
80                                           joinOp );
81       p();
82     } catch( Exception e ) {
83       f();
84     }
85
86     
87     builder =
88       new MultiViewMapBuilder<Integer>( new Class[] 
89                                         {Integer.class,
90                                          Boolean.class,
91                                          Integer.class,
92                                          String.class},
93                                         joinOp );
94
95     try {
96       // can't build a map with no views yet
97       builder.build();
98       f();
99     } catch( Exception expected ) {
100       p();   
101     }
102
103     try {
104       builder.addPartialView();
105       f();
106     } catch( IllegalArgumentException expected ) {
107       p();   
108     } catch( Exception e ) {
109       f();
110     }
111
112     try {
113       // an index is out of bounds for this multikey (0-3)
114       builder.addPartialView( 1, 6 );
115       f();
116     } catch( IllegalArgumentException expected ) {
117       p();   
118     } catch( Exception e ) {
119       f();
120     }
121
122     try {
123       // an index is out of bounds for this multikey (0-3)
124       builder.addPartialView( 2, -1, 3 );
125       f();
126     } catch( IllegalArgumentException expected ) {
127       p();   
128     } catch( Exception e ) {
129       f();
130     }
131
132     try {
133       // an index is specified more than once
134       builder.addPartialView( 0, 3, 0 );
135       f();
136     } catch( IllegalArgumentException expected ) {
137       p();   
138     } catch( Exception e ) {
139       f();
140     }
141
142     try {
143       // the full view is implicit
144       builder.addPartialView( 0, 1, 2, 3 );
145       f();
146     } catch( IllegalArgumentException expected ) {
147       p();   
148     } catch( Exception e ) {
149       f();
150     }
151
152     try {
153       builder.addPartialView( 1, 3 );
154       p();
155     } catch( Exception e ) {
156       f();
157     }
158
159     try {
160       builder.addPartialView( 0, 1, 3 );
161       p();
162     } catch( Exception e ) {
163       f();
164     }
165
166     try {
167       // duplicate view
168       builder.addPartialView( 1, 3 );
169       f();
170     } catch( IllegalArgumentException expected ) {
171       p();   
172     } catch( Exception e ) {
173       f();
174     }
175     System.out.println( "DONE" );
176   }
177
178
179   public static void testMap() {    
180     System.out.println( "Testing MultiViewMap..." );
181     
182     Map<MultiKey, Integer> expected;
183
184     MultiViewMapBuilder<Integer> builder =
185       new MultiViewMapBuilder<Integer>( new Class[] 
186                                         {Integer.class,   // key0
187                                          Boolean.class,   // key1
188                                          String.class},   // key2
189                                         joinOp );
190     final BitSet view012 = builder.getFullView();
191     final BitSet view01  = builder.addPartialView( 0, 1 );
192     final BitSet view0   = builder.addPartialView( 0 );
193     final BitSet view2   = builder.addPartialView( 2 );
194     builder.setCheckTypes( true );
195     builder.setCheckConsistency( true );
196
197     MultiViewMap<Integer> mapA = builder.build();
198
199
200     // Simple put and remove
201     MultiKey partialKey4 = MultiKey.factory( 4 );
202     expected = new HashMap<MultiKey, Integer>();
203     verify( expected, mapA.get( view0, partialKey4 ) );
204
205     MultiKey vader = MultiKey.factory( 4, true, "Vader" );
206     mapA.put( vader, 1001 );
207     expected = new HashMap<MultiKey, Integer>();
208     expected.put( vader, 1001 );
209     verify( expected, mapA.get( view0, partialKey4 ) );
210
211     mapA.remove( view0, partialKey4 );
212     expected = new HashMap<MultiKey, Integer>();
213     verify( expected, mapA.get( view0, partialKey4 ) );
214
215
216     // Try across a merge
217     mapA.put( vader, 1001 );
218     expected = new HashMap<MultiKey, Integer>();
219     expected.put( vader, 1001 );
220     verify( expected, mapA.get( view0, partialKey4 ) );
221
222     MultiViewMap<Integer> mapB = builder.build();
223     expected = new HashMap<MultiKey, Integer>();
224     verify( expected, mapB.get( view0, partialKey4 ) );
225
226     mapB.merge( mapA );
227     expected = new HashMap<MultiKey, Integer>();
228     expected.put( vader, 1001 );
229     verify( expected, mapB.get( view0, partialKey4 ) );
230
231     
232     // Remove the correct entries
233     MultiKey luke = MultiKey.factory( 5, true,  "Luke" );
234     MultiKey han  = MultiKey.factory( 4, true,  "Han Solo" );
235     MultiKey r2   = MultiKey.factory( 4, false, "R2-D2" );
236
237     mapA.put( luke, 1002 );
238     mapA.put( han,  1003 );
239     mapA.put( r2,   1004 );
240     expected = new HashMap<MultiKey, Integer>();
241     expected.put( vader, 1001 );
242     expected.put( han,   1003 );
243     expected.put( r2,    1004 );
244     verify( expected, mapA.get( view0, partialKey4 ) );
245
246
247     // Get for full keys didn't work in production,
248     // so test it explicitly
249     expected = new HashMap<MultiKey, Integer>();
250     expected.put( luke, 1002 );
251     verify( expected, mapA.get( view012, luke ) );
252
253
254     // removes vader and han
255     MultiKey partialKey4true = MultiKey.factory( 4, true );
256     mapA.remove( view01, partialKey4true );
257     
258     expected = new HashMap<MultiKey, Integer>();
259     expected.put( r2, 1004 );
260     verify( expected, mapA.get( view0, partialKey4 ) );
261
262     MultiKey partialKeyLuke = MultiKey.factory( "Luke" );
263     expected = new HashMap<MultiKey, Integer>();
264     expected.put( luke, 1002 );
265     verify( expected, mapA.get( view2, partialKeyLuke ) );
266
267
268     System.out.println( "DONE" );
269   }
270
271
272   public static void stressTest() {
273     System.out.println( "Stressing MultiViewMap..." );
274
275     // Just pound away with operations to see if we can crash anything.
276
277     MultiViewMapBuilder<Integer> builder =
278       new MultiViewMapBuilder<Integer>( new Class[] 
279                                         {Integer.class,   // key0
280                                          Boolean.class,   // key1
281                                          String.class},   // key2
282                                         joinOp );
283     builder.setCheckTypes( true );
284     builder.setCheckConsistency( true );
285
286     Integer[] ints = new Integer[] {
287       1, 2, 3, 4, 5, 6, 7,
288     };
289
290     Boolean[] bools = new Boolean[] {
291       true, false, false, // skew distribution
292     };
293
294     String[] strs = new String[] {
295       "Vader", "Han Solo", "R2-D2", "Luke", "Leia",
296     };
297
298     final BitSet view012 = builder.getFullView();
299     final BitSet view01  = builder.addPartialView( 0, 1 );
300     final BitSet view12  = builder.addPartialView( 1, 2 );
301     final BitSet view02  = builder.addPartialView( 0, 2 );
302     final BitSet view0   = builder.addPartialView( 0 );
303     final BitSet view1   = builder.addPartialView( 1 );
304     final BitSet view2   = builder.addPartialView( 2 );
305
306     // This might be the ugliest line of Java I've ever written.  BARF
307     @SuppressWarnings({"unchecked"})
308     MultiViewMap<Integer>[] maps = 
309       (MultiViewMap<Integer>[]) Array.newInstance( builder.build().getClass(), 8 );
310
311     for( int i = 0; i < maps.length; ++i ) {
312       maps[i] = builder.build();
313     }
314
315
316     //System.out.println( "    Number of full keys in each table per op cycle:" );
317     
318     for( int reps = 0; reps < 100; ++reps ) {
319       int nextOp = random.nextInt( 100 );
320
321       //System.out.print( "    Op: " );
322
323       if( nextOp < 15 ) {
324         // put some new values in
325         //System.out.print( "PT  " );
326         int numNewValues = 1 + random.nextInt( 8 );
327         for( int i = 0; i < numNewValues; ++i ) {
328           MultiKey newKey = MultiKey.factory( getInt( ints ),
329                                               getBool( bools ),
330                                               getStr( strs ) );
331           getMap( maps ).put( newKey, random.nextInt() );
332         }
333
334       } else if( nextOp < 70 ) {
335         // remove values by a random view
336         //System.out.print( "RM  " );
337         MultiViewMap<Integer> map = getMap( maps );
338
339         switch( random.nextInt( 6 ) ) {
340         case 0: { map.remove( view0,  MultiKey.factory( getInt (ints ) ) ); } break;
341         case 1: { map.remove( view1,  MultiKey.factory( getBool(bools) ) ); } break;
342         case 2: { map.remove( view2,  MultiKey.factory( getStr (strs ) ) ); } break;
343         case 3: { map.remove( view01, MultiKey.factory( getInt (ints ), getBool(bools) ) ); } break;
344         case 4: { map.remove( view12, MultiKey.factory( getBool(bools), getStr (strs ) ) ); } break;
345         case 5: { map.remove( view02, MultiKey.factory( getInt (ints ), getStr (strs ) ) ); } break;
346         }
347
348       } else {
349         // merge two tables
350         //System.out.print( "MG  " );
351         getMap( maps ).merge( getMap( maps ) );
352       }   
353
354       for( int i = 0; i < maps.length - 1; ++i ) {
355         if( i < maps.length - 1 ) {
356           //System.out.print( maps[i].size() + ", " );
357         }
358       }
359       //System.out.println( maps[maps.length-1].size() );
360     }
361
362     System.out.println( "DONE" );
363   }
364
365   private static Integer getInt( Integer[] ints ) {
366     return ints[random.nextInt( ints.length )];
367   }
368
369   private static Boolean getBool( Boolean[] bools ) {
370     return bools[random.nextInt( bools.length )];
371   }
372
373   private static String getStr( String[] strs ) {
374     return strs[random.nextInt( strs.length )];
375   }
376
377   private static MultiViewMap<Integer> getMap( MultiViewMap<Integer>[] maps ) {
378     return maps[random.nextInt( maps.length )];
379   }
380 }