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