001/** 002 * This is part of HW0: Environment Setup and Java Introduction for CSE 331. 003 */ 004package hw3.test; 005import hw3.*; 006 007import java.util.Iterator; 008import java.util.LinkedList; 009import java.util.Random; 010import java.util.Set; 011import java.util.HashSet; 012 013import org.junit.Test; 014import org.junit.BeforeClass; 015import static org.junit.Assert.*; 016import static org.hamcrest.Matchers.greaterThan; 017 018/** 019 * BoxTest is a glassbox test of the Box class. 020 * 021 * Recall that like a BallContainer, the Box is a container for Balls and you 022 * can only put a Ball into a Box once. After you put the Ball into 023 * the Box, further attempts to do so will fail, since the Ball is 024 * already in the Box! Similarly, you cannot expect to remove a Ball 025 * from a Box if it is not inside the Box. 026 * 027 * In addition, a Box differs from a ballcontainer because it only has a finite 028 * volume. As Balls get put into a Box, it gets filled up. Once a Box 029 * is full, further attempts to put Balls into the Box will also fail. 030 * 031 * @see hw3.Ball 032 * @see hw3.BallContainer 033 * @see hw3.Box 034 */ 035@SuppressWarnings("nullness") 036public class BoxTest { 037 038 private static Box box = null; 039 private static Ball[] b = null; 040 041 private static final int NUM_BALLS_TO_TEST = 5; 042 private static final int BOX_CAPACITY = NUM_BALLS_TO_TEST - 1; 043 private static final double BALL_UNIT_VOLUME = 10.0; 044 private static final double JUNIT_DOUBLE_DELTA = 0.0001; 045 private static final int TRIES_FOR_BALLS_TEST = 3; 046 047 @BeforeClass 048 public static void setupBeforeTests() throws Exception { 049 assertThat("Test case error, you must test at least 1 Ball!!", 050 NUM_BALLS_TO_TEST, greaterThan(0)); 051 assertThat("This test case is set up assuming that the box cannot contain all the balls, please check and change parameters!", 052 NUM_BALLS_TO_TEST, greaterThan(BOX_CAPACITY)); 053 054 double box_volume = 0; 055 056 // Let's create the balls we need. 057 b = new Ball[NUM_BALLS_TO_TEST]; 058 for (int i=0; i<NUM_BALLS_TO_TEST; i++) { 059 if (i<BOX_CAPACITY) { 060 box_volume += (i+1)*BALL_UNIT_VOLUME; 061 } 062 b[i] = new Ball((i+1)*BALL_UNIT_VOLUME); 063 } 064 065 // Now, we create the box once we figure out how big a box we 066 // need. 067 box = new Box(box_volume); 068 069 } 070 071 /** Test to check that Box.add(Ball) is implemented correctly */ 072 @Test 073 public void testAdd() { 074 box.clear(); 075 for (int i=0; i<BOX_CAPACITY; i++) { 076 assertTrue("Box.add(Ball) failed to add a new Ball!", 077 box.add(b[i])); 078 assertFalse("Box.add(Ball) seems to allow the same Ball to be added twice!", 079 box.add(b[i])); 080 assertTrue("Box does not contain a ball after it is supposed to have been added!", 081 box.contains(b[i])); 082 } 083 for (int i=BOX_CAPACITY; i<NUM_BALLS_TO_TEST; i++) { 084 assertFalse("Box.add(Ball) allows a Ball to be added even though it is already full!", 085 box.add(b[i])); 086 } 087 } 088 089 /** Test to check that Box.getBallsFromSmallest() is implemented correctly */ 090 @Test 091 public void testGetBalls() { 092 Random rnd = new Random(); 093 094 for (int k=0; k<TRIES_FOR_BALLS_TEST; k++) { 095 096 box.clear(); 097 098 // Let's put all the balls into a list. 099 LinkedList<Ball> list = new LinkedList<Ball>(); 100 for (int i=0; i<BOX_CAPACITY; i++) { 101 list.add(b[i]); 102 } 103 104 // First we add the balls to the box in some random order. 105 for (int i=0; i<BOX_CAPACITY; i++) { 106 box.add(list.remove(rnd.nextInt(list.size()))); 107 } 108 109 int contentsSize = box.size(); 110 // Next we call the iterator and check that the balls come out 111 // in the correct order. 112 Iterator<Ball> it = box.getBallsFromSmallest(); 113 int count = 0; 114 while (it.hasNext() && count < BOX_CAPACITY) { 115 Ball ball = it.next(); 116 assertEquals("Balls are not returned by Box.getBallsFromSmallest() iterator in the correct order", 117 b[count], ball); 118 if (b[count] != ball) { 119 break; 120 } 121 count++; 122 } 123 assertEquals("Box.getBallsFromSmallest() did not return all the balls", 124 BOX_CAPACITY, count); 125 assertEquals("Number of balls in box was modified", 126 contentsSize, box.size()); 127 } 128 } 129 130 /** 131 * Test to check that Box.remove(Ball) is implemented 132 * correctly. Depending on how <code>getBallsFromSmallest()</code> 133 * is implemented, remove() might have to be overridden and this 134 * test helps ensure that remove() is not broken in the process. 135 */ 136 @Test 137 public void testRemove() { 138 box.clear(); 139 assertFalse("Box.remove(Ball) should fail because box is empty, but it didn't!", 140 box.remove(b[0])); 141 for (int i=0; i<BOX_CAPACITY; i++) { 142 box.clear(); 143 for (int j=0; j<i; j++) { 144 box.add(b[j]); 145 } 146 for (int j=0; j<i; j++) { 147 assertTrue("Box.remove(Ball) failed to remove a Ball that is supposed to be inside", 148 box.remove(b[j])); 149 assertFalse("Box still contains a ball after it is supposed to have been removed!", 150 box.contains(b[j])); 151 } 152 for (int j=i; j<NUM_BALLS_TO_TEST; j++) { 153 assertFalse("Box.remove(Ball) did not fail for a Ball that is not inside", 154 box.remove(b[j])); 155 } 156 } 157 } 158 159 160 /** Test to check that Box.clear() is implemented correctly */ 161 @Test 162 public void testClear() { 163 box.clear(); 164 assertEquals("Box is not empty after being cleared!", 0, box.size()); 165 box.add(b[0]); 166 box.clear(); 167 assertEquals("Box is not empty after being cleared!", 0, box.size()); 168 } 169 170 /** Test to check that check that we can put a Ball into a Box */ 171 @Test 172 public void testVolume() { 173 box.clear(); 174 assertEquals("Volume of empty Box is not zero!", 175 0, box.getVolume(), JUNIT_DOUBLE_DELTA); 176 for (int i=0; i<BOX_CAPACITY; i++) { 177 box.add(b[i]); 178 assertEquals("Volume of Box with one ball", 179 (i+1)*(i+2)*BALL_UNIT_VOLUME/2, box.getVolume(), 180 JUNIT_DOUBLE_DELTA); 181 } 182 } 183 184 /** Test to check that size() returns the correct number. */ 185 @Test 186 public void testSize() { 187 box.clear(); 188 assertEquals("size() of empty Box is not zero!", 0, box.size()); 189 for (int i=0; i<BOX_CAPACITY; i++) { 190 box.add(b[i]); 191 assertEquals("size() of Box with "+(i+1)+" ball(s)", 192 i+1, box.size()); 193 } 194 } 195 196 /** Test to check that size() returns the correct number. */ 197 @Test 198 public void testContains() { 199 box.clear(); 200 for (int i=0; i<BOX_CAPACITY; i++) { 201 assertFalse("Empty Box seems to contain a ball!", 202 box.contains(b[i])); 203 } 204 for (int i=0; i<BOX_CAPACITY; i++) { 205 box.add(b[i]); 206 assertTrue("Box does not contain a Ball that is supposed to be inside!", 207 box.contains(b[i])); 208 for (int j=i+1; j<BOX_CAPACITY; j++) { 209 assertFalse("Box seems to contain a Ball that is not inside!", 210 box.contains(b[j])); 211 } 212 } 213 } 214 215 /** 216 * Test to check that iterator() is implemented correctly. 217 */ 218 @Test 219 public void testIterator() { 220 Set<Ball> allBalls = new HashSet<Ball>(); 221 Set<Ball> seenBalls = new HashSet<Ball>(); 222 box.clear(); 223 for (Ball aBall : b) { 224 box.add(aBall); 225 allBalls.add(aBall); 226 } 227 int i = 0; 228 for (Ball aBall : box) { 229 assertTrue("Iterator returned a ball that isn't in the container: " + aBall, 230 allBalls.contains(aBall)); 231 assertFalse("Iterator returned the same ball twice: " + aBall, 232 seenBalls.contains(aBall)); 233 seenBalls.add(aBall); 234 i++; 235 } 236 assertEquals("BallContainer iterator did not return enough items!", 237 b.length-1, i); 238 } 239}