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