Skip to content

Commit b188011

Browse files
committed
0.6 Update
This changes does not change functionality and will not break any implementation. All changes are internal only. Changes to Collection Class: 1) Updated contains to just use collection.stream.anyMatch 2) Added parameter guards to protect against invalid elements 3) get() will throw an illegal state exception if the collection is empty 4) get() asserts object is not null (Which if the collection contains elements, it never should be). 5) JavaDoc has been updated to document these changes Changes to Tests: 1) Added new tests to assert all errors are thrown correctly 2) Added new test to assert get() never returns null in extreme edge cases 3) Increased repeated test amounts 4) Updated int comparison to use assertEquals not assertTrue x == y
1 parent 75d2f12 commit b188011

File tree

2 files changed

+155
-45
lines changed

2 files changed

+155
-45
lines changed

src/main/java/com/lewdev/probabilitylib/ProbabilityCollection.java

+47-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Comparator;
44
import java.util.Iterator;
5+
import java.util.Objects;
56
import java.util.TreeSet;
67
import java.util.concurrent.ThreadLocalRandom;
78

@@ -22,7 +23,7 @@
2223
* </ul>
2324
*
2425
* @author Lewys Davies
25-
* @version 0.5
26+
* @version 0.6
2627
*
2728
* @param <E> Type of elements
2829
*/
@@ -60,12 +61,15 @@ public boolean isEmpty() {
6061
/**
6162
* @param object
6263
* @return True if the collection contains the object, else False
64+
* @throws IllegalArgumentException if object null
6365
*/
6466
public boolean contains(E object) {
67+
if(object == null) {
68+
throw new IllegalArgumentException("Cannot check if null object is contained in a collection");
69+
}
70+
6571
return this.collection.stream()
66-
.filter(entry -> entry.getObject().equals(object))
67-
.findFirst()
68-
.isPresent();
72+
.anyMatch(entry -> entry.getObject().equals(object));
6973
}
7074

7175
/**
@@ -78,12 +82,24 @@ public Iterator<ProbabilitySetElement<E>> iterator() {
7882
/**
7983
* Add an object to this collection
8084
*
81-
* @param object
82-
* @param probability share
85+
* @param object. Not null.
86+
* @param probability share. Must be greater than 0.
87+
*
88+
* @throws IllegalArgumentException if object is null
89+
* @throws IllegalArgumentException if probability <= 0
8390
*/
8491
public void add(E object, int probability) {
92+
if(object == null) {
93+
throw new IllegalArgumentException("Cannot add null object");
94+
}
95+
96+
if(probability <= 0) {
97+
throw new IllegalArgumentException("Probability must be greater than 0");
98+
}
99+
85100
this.collection.add(new ProbabilitySetElement<E>(object, probability));
86101
this.totalProbability += probability;
102+
87103
this.updateIndexes();
88104
}
89105

@@ -92,32 +108,46 @@ public void add(E object, int probability) {
92108
*
93109
* @param object
94110
* @return True if object was removed, else False.
111+
*
112+
* @throws IllegalArgumentException if object null
95113
*/
96114
public boolean remove(E object) {
115+
if(object == null) {
116+
throw new IllegalArgumentException("Cannot remove null object");
117+
}
118+
97119
Iterator<ProbabilitySetElement<E>> it = this.iterator();
98-
boolean removed = false;
120+
boolean removed = it.hasNext();
99121

100122
while(it.hasNext()) {
101-
ProbabilitySetElement<E> element = it.next();
102-
if(element.getObject().equals(object)) {
103-
removed = true;
104-
this.totalProbability -= element.getProbability();
123+
ProbabilitySetElement<E> entry = it.next();
124+
if(entry.getObject().equals(object)) {
125+
this.totalProbability -= entry.getProbability();
105126
it.remove();
106127
}
107128
}
108129

109130
this.updateIndexes();
131+
110132
return removed;
111133
}
112134

113135
/**
114-
* @return Random object based on probability
136+
* Get a random object from this collection, based on probability.
137+
*
138+
* @return <E> Random object
139+
*
140+
* @throws IllegalStateException if this collection is empty
115141
*/
116142
public E get() {
143+
if(this.isEmpty()) {
144+
throw new IllegalStateException("Cannot get an element out of a empty set");
145+
}
146+
117147
ProbabilitySetElement<E> toFind = new ProbabilitySetElement<>(null, 0);
118148
toFind.setIndex(ThreadLocalRandom.current().nextInt(1, this.totalProbability + 1));
119149

120-
return this.collection.floor(toFind).getObject();
150+
return Objects.requireNonNull(this.collection.floor(toFind).getObject());
121151
}
122152

123153
/**
@@ -131,7 +161,8 @@ public final int getTotalProbability() {
131161
* Calculate the size of all element's "block" of space:
132162
* i.e 1-5, 6-10, 11-14, 15, 16
133163
*
134-
* We then only need to store the start index of each element
164+
* We then only need to store the start index of each element,
165+
* as we make use of the TreeSet#floor
135166
*/
136167
private void updateIndexes() {
137168
int previousIndex = 0;
@@ -182,12 +213,12 @@ public final int getProbability() {
182213
}
183214

184215
// Used internally, see this class's documentation
185-
protected final int getIndex() {
216+
private final int getIndex() {
186217
return this.index;
187218
}
188219

189220
// Used Internally, see this class's documentation
190-
protected final int setIndex(int index) {
221+
private final int setIndex(int index) {
191222
this.index = index;
192223
return this.index;
193224
}

src/test/java/com/lewdev/probabilitylib/ProbabilityCollectionTest.java

+108-29
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import static org.junit.jupiter.api.Assertions.*;
44

55
import org.junit.jupiter.api.RepeatedTest;
6+
import org.junit.jupiter.api.Test;
67

78
/**
89
* @author Lewys Davies
910
*/
1011
public class ProbabilityCollectionTest {
1112

12-
@RepeatedTest(value = 1000)
13+
@RepeatedTest(value = 10_000)
1314
public void test_insert() {
1415
ProbabilityCollection<String> collection = new ProbabilityCollection<>();
1516
assertEquals(0, collection.size());
@@ -44,12 +45,12 @@ public void test_insert() {
4445
}
4546
}
4647

47-
@RepeatedTest(value = 1000)
48+
@RepeatedTest(value = 10_000)
4849
public void test_remove() {
4950
ProbabilityCollection<String> collection = new ProbabilityCollection<>();
50-
assertTrue(collection.size() == 0);
51+
assertEquals(0, collection.size());
5152
assertTrue(collection.isEmpty());
52-
assertTrue(collection.getTotalProbability() == 0);
53+
assertEquals(0, collection.getTotalProbability());
5354

5455
String t1 = "Hello";
5556
String t2 = "World";
@@ -59,33 +60,36 @@ public void test_remove() {
5960
collection.add(t2, 10);
6061
collection.add(t3, 10);
6162

62-
assertTrue(collection.size() == 3);
63+
assertEquals(3, collection.size());
6364
assertFalse(collection.isEmpty());
64-
assertTrue(collection.getTotalProbability() == 30);
65+
assertEquals(30, collection.getTotalProbability());
6566

66-
collection.remove(t2);
67+
// Remove t2
68+
assertTrue(collection.remove(t2));
6769

68-
assertTrue(collection.size() == 2);
70+
assertEquals(2, collection.size());
6971
assertFalse(collection.isEmpty());
70-
assertTrue(collection.getTotalProbability() == 20);
72+
assertEquals(20, collection.getTotalProbability());
7173

72-
collection.remove(t1);
74+
// Remove t1
75+
assertTrue(collection.remove(t1));
7376

74-
assertTrue(collection.size() == 1);
77+
assertEquals(1, collection.size());
7578
assertFalse(collection.isEmpty());
76-
assertTrue(collection.getTotalProbability() == 10);
79+
assertEquals(10, collection.getTotalProbability());
7780

78-
collection.remove(t3);
81+
//Remove t3
82+
assertTrue(collection.remove(t3));
7983

80-
assertTrue(collection.size() == 0);
81-
assertTrue(collection.getTotalProbability() == 0);
84+
assertEquals(0, collection.size());
8285
assertTrue(collection.isEmpty());
86+
assertEquals(0, collection.getTotalProbability());
8387
}
8488

85-
@RepeatedTest(value = 1000)
89+
@RepeatedTest(value = 10_000)
8690
public void test_remove_duplicates() {
8791
ProbabilityCollection<String> collection = new ProbabilityCollection<>();
88-
assertTrue(collection.size() == 0);
92+
assertEquals(0, collection.size());
8993
assertTrue(collection.isEmpty());
9094

9195
String t1 = "Hello";
@@ -104,27 +108,30 @@ public void test_remove_duplicates() {
104108
collection.add(t3, 10);
105109
}
106110

107-
assertTrue(collection.size() == 30);
111+
assertEquals(30, collection.size());
108112
assertFalse(collection.isEmpty());
109-
assertTrue(collection.getTotalProbability() == 300);
113+
assertEquals(300, collection.getTotalProbability());
110114

111-
collection.remove(t2);
115+
//Remove t2
116+
assertTrue(collection.remove(t2));
112117

113-
assertTrue(collection.size() == 20);
118+
assertEquals(20, collection.size());
114119
assertFalse(collection.isEmpty());
115-
assertTrue(collection.getTotalProbability() == 200);
120+
assertEquals(200, collection.getTotalProbability());
116121

117-
collection.remove(t1);
122+
// Remove t1
123+
assertTrue(collection.remove(t1));
118124

119-
assertTrue(collection.size() == 10);
125+
assertEquals(10, collection.size());
120126
assertFalse(collection.isEmpty());
127+
assertEquals(100, collection.getTotalProbability());
121128

122-
assertTrue(collection.getTotalProbability() == 100);
123-
collection.remove(t3);
129+
//Remove t3
130+
assertTrue(collection.remove(t3));
124131

125-
assertTrue(collection.size() == 0);
132+
assertEquals(0, collection.size());
126133
assertTrue(collection.isEmpty());
127-
assertTrue(collection.getTotalProbability() == 0);
134+
assertEquals(0, collection.getTotalProbability());
128135
}
129136

130137
@RepeatedTest(1_000_000)
@@ -159,10 +166,82 @@ public void test_probability() {
159166
double bResult = b / (double) totalGets * 100;
160167
double cResult = c / (double) totalGets * 100;
161168

162-
double acceptableDeviation = 1;
169+
double acceptableDeviation = 1; // %
163170

164171
assertTrue(Math.abs(aProb - aResult) <= acceptableDeviation);
165172
assertTrue(Math.abs(bProb - bResult) <= acceptableDeviation);
166173
assertTrue(Math.abs(cProb - cResult) <= acceptableDeviation);
167174
}
175+
176+
@RepeatedTest(1_000_000)
177+
public void test_get_never_null() {
178+
ProbabilityCollection<String> collection = new ProbabilityCollection<>();
179+
// Tests get will never return null
180+
// Just one smallest element get, must not return null
181+
collection.add("A", 1);
182+
assertNotNull(collection.get());
183+
184+
// Reset state
185+
collection.remove("A");
186+
assertEquals(0, collection.size());
187+
assertTrue(collection.isEmpty());
188+
189+
// Just one large element, must not return null
190+
collection.add("A", 5_000_000);
191+
assertNotNull(collection.get());
192+
}
193+
194+
@Test
195+
public void test_Errors() {
196+
ProbabilityCollection<String> collection = new ProbabilityCollection<>();
197+
198+
assertEquals(0, collection.size());
199+
assertTrue(collection.isEmpty());
200+
assertEquals(0, collection.getTotalProbability());
201+
202+
// Cannot get from empty collection
203+
assertThrows(IllegalStateException.class, () -> {
204+
collection.get();
205+
});
206+
207+
assertEquals(0, collection.size());
208+
assertTrue(collection.isEmpty());
209+
assertEquals(0, collection.getTotalProbability());
210+
211+
// Cannot add null object
212+
assertThrows(IllegalArgumentException.class, () -> {
213+
collection.add(null, 1);
214+
});
215+
216+
assertEquals(0, collection.size());
217+
assertTrue(collection.isEmpty());
218+
assertEquals(0, collection.getTotalProbability());
219+
220+
// Cannot add prob 0
221+
assertThrows(IllegalArgumentException.class, () -> {
222+
collection.add("A", 0);
223+
});
224+
225+
assertEquals(0, collection.size());
226+
assertTrue(collection.isEmpty());
227+
assertEquals(0, collection.getTotalProbability());
228+
229+
// Cannot remove null
230+
assertThrows(IllegalArgumentException.class, () -> {
231+
collection.remove(null);
232+
});
233+
234+
assertEquals(0, collection.size());
235+
assertTrue(collection.isEmpty());
236+
assertEquals(0, collection.getTotalProbability());
237+
238+
// Cannot contains null
239+
assertThrows(IllegalArgumentException.class, () -> {
240+
collection.contains(null);
241+
});
242+
243+
assertEquals(0, collection.size());
244+
assertTrue(collection.isEmpty());
245+
assertEquals(0, collection.getTotalProbability());
246+
}
168247
}

0 commit comments

Comments
 (0)