]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.runtime/tests/org/simantics/scl/runtime/tests/TestCHRHashIndex.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scl.runtime / tests / org / simantics / scl / runtime / tests / TestCHRHashIndex.java
1 package org.simantics.scl.runtime.tests;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.LinkedHashSet;
6 import java.util.List;
7 import java.util.Random;
8
9 import org.junit.Assert;
10 import org.junit.Before;
11 import org.junit.Test;
12 import org.simantics.scl.runtime.chr.CHRHashIndex;
13
14 import gnu.trove.map.hash.TIntObjectHashMap;
15 import gnu.trove.set.hash.THashSet;
16 import gnu.trove.set.hash.TIntHashSet;
17
18 public class TestCHRHashIndex {
19     
20     Random random;
21     Store store;
22     Store2 store2;
23     THashSet<Fact> aliveFacts = new THashSet<Fact>(); 
24     
25     public static class Store {
26         CHRHashIndex bfIndex = new CHRHashIndex() {
27             @Override
28             protected boolean keyEquals(Object a, Object b) {
29                 return ((Fact)a).a == ((Fact)b).a;
30             }
31             @Override
32             protected int keyHashCode(Object key) {
33                 return ((Fact)key).a;
34             }
35         };
36     }
37     
38     public static class Store2 {
39         TIntObjectHashMap<LinkedHashSet<Fact>> bfIndex = new TIntObjectHashMap<LinkedHashSet<Fact>>(); 
40     }
41     
42     public static class Fact {
43         public int a; // key
44         public int b;
45         public Fact bfPrev;
46         public Fact bfNext;
47         
48         public Fact(int a, int b) {
49             this.a = a;
50             this.b = b;
51         }
52         
53         public void add(Store store) {
54             bfNext = (Fact)store.bfIndex.addFreshAndReturnOld(this);
55             if(bfNext != null)
56                 bfNext.bfPrev = this;
57         }
58         
59         public void remove(Store store) {
60             if(bfPrev == null) {
61                 if(bfNext == null)
62                     store.bfIndex.removeKnownToExistKey(this);
63                 else {
64                     bfNext.bfPrev = null;
65                     store.bfIndex.replaceKnownToExistKey(this, bfNext);
66                 }
67             }
68             else {
69                 bfPrev.bfNext = bfNext;
70                 if(bfNext != null)
71                     bfNext.bfPrev = bfPrev;
72             }
73         }
74         
75         public List<Fact> get(Store store) {
76             Object r = store.bfIndex.getEqual(this);
77             if(r == null)
78                 return Collections.emptyList();
79             else {
80                 ArrayList<Fact> result = new ArrayList<Fact>(); 
81                 for(Fact cur=(Fact)r;cur!=null;cur=cur.bfNext)
82                     result.add(cur);
83                 Collections.reverse(result);
84                 return result;
85             }
86         }
87         
88         public void add(Store2 store) {
89             LinkedHashSet<Fact> set = store.bfIndex.get(a);
90             if(set == null) {
91                 set = new LinkedHashSet<>();
92                 store.bfIndex.put(a, set);
93             }
94             set.add(this);
95         }
96         
97         public void remove(Store2 store) {
98             store.bfIndex.get(a).remove(this);
99         }
100         
101         public List<Fact> get(Store2 store) {
102             LinkedHashSet<Fact> set = store.bfIndex.get(a);
103             if(set == null)
104                 return Collections.emptyList();
105             else
106                 return new ArrayList<Fact>(set);
107         }
108     }
109     
110     @Before
111     public void init() {
112         random = new Random(123L);
113         store = new Store();
114         store2 = new Store2();
115     }
116     
117     public Fact createFact(int maxA, int maxB) {
118         return new Fact(random.nextInt(maxA), random.nextInt(maxB));
119     }
120     
121     public void add(Fact fact) {
122         fact.add(store);
123         fact.add(store2);
124         aliveFacts.add(fact);
125     }
126     
127     public void remove(Fact fact) {
128         fact.remove(store);
129         fact.remove(store2);
130         aliveFacts.remove(fact);
131     }
132     
133     public void checkConsistency() {
134         TIntHashSet keys = new TIntHashSet();
135         for(Fact fact : aliveFacts)
136             keys.add(fact.a);
137         Fact temp = new Fact(0, 0);
138         for(int a : keys.toArray()) {
139             temp.a = a;
140             Assert.assertEquals(temp.get(store2), temp.get(store));
141         }
142         TIntHashSet keys2 = new TIntHashSet();
143         for(Fact fact : store.bfIndex.toArray(new Fact[keys.size()]))
144             keys2.add(fact.a);
145         Assert.assertEquals(keys, keys2);
146     }
147     
148     @Test
149     public void testStore() {
150         for(int i=0;;++i) {
151             System.out.println("Run " + i);
152             for(int j=0;j<1000000;++j)
153                 add(createFact(10000, 1000000));
154             checkConsistency();
155             ArrayList<Fact> factArray = new ArrayList<Fact>(aliveFacts);
156             Collections.shuffle(factArray, random);
157             for(Fact fact : factArray.subList(100000, factArray.size()))
158                 remove(fact);
159             checkConsistency();
160         }
161     }
162     
163 }