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