001package edu.pdx.cs.joy;
002
003import org.junit.jupiter.api.Test;
004
005import java.util.AbstractMap;
006import java.util.Iterator;
007import java.util.NoSuchElementException;
008
009import static org.junit.jupiter.api.Assertions.*;
010
011/**
012 * This is a set of JUnit unit tests that test the functionality of an
013 * {@link AbstractLRUMap LRU Map}.
014 */
015public abstract class LRUMapTestCase {
016
017  /**
018   * A factory method that creates a new instance of the LRU Map to be tested.
019   *
020   * @param capacity The maximum number of mappings in the newly-created LRU
021   *                 map
022   * @return A new LRU Map with the given capacity
023   * @throws IllegalArgumentException A map cannot be created
024   */
025  public abstract <K, V> AbstractLRUMap<K, V> createLRUMap(int capacity);
026
027  /**
028   * Tests creating a new LRU Map
029   *
030   * @see LRUMapTestCase#createLRUMap(int)
031   */
032  @Test
033  public void testCreate() {
034    createLRUMap(4);
035  }
036
037  /**
038   * Tests the {@link AbstractLRUMap#getStudentNames()} methods
039   */
040  @Test
041  public void testGetStudentNames() {
042    AbstractLRUMap map =
043      createLRUMap(4);
044    Iterator students = map.getStudentNames().iterator();
045    System.out.println("\n\nImplemented by:");
046    while (students.hasNext()) {
047      System.out.println("  " + students.next());
048    }
049    System.out.println("\n");
050  }
051
052  /**
053   * Tests that the size of the LRU map is bounded
054   *
055   * @see AbstractLRUMap#put(Object, Object)
056   */
057  @Test
058  public void testMapSizeIsBounded() {
059    int maxMappings = 4;
060    AbstractLRUMap<Integer, String> map =
061      createLRUMap(maxMappings);
062    assertEquals(0, map.size());
063
064    for (int i = 0; i < maxMappings; i++) {
065      map.put(i, String.valueOf(i));
066      assertEquals(i + 1, map.size());
067    }
068
069    map.put(maxMappings + 1,
070      String.valueOf(maxMappings + 1));
071
072    assertEquals(maxMappings, map.size());
073  }
074
075  /**
076   * Makes sure that entrySet() Iterator iterates
077   *
078   * @see AbstractMap#containsKey(Object)
079   */
080  @Test
081  public void testLRUMappingIterates() {
082    int maxMappings = 4;
083    AbstractLRUMap<Integer, String> map =
084      createLRUMap(maxMappings);
085    assertEquals(0, map.size());
086
087    for (int i = 0; i < maxMappings; i++) {
088      map.put(i, String.valueOf(i));
089      assertEquals(i + 1, map.size());
090    }
091
092    try {
093      // get the iterator for this map's mappings 
094      Iterator iter = map.entrySet().iterator();
095
096      // iterate through the mappings 
097      for (int i = 0; i < maxMappings; i++) {
098        iter.next();
099      }
100
101      // there should be no more mappings so this should              
102      // throw a NoSuchElementException error                         
103      iter.next();
104      System.out.println("Bad iterator returned by entrySet()."
105        + "\nFix before continuing unit tests.");
106      System.exit(1);
107
108    } catch (IndexOutOfBoundsException ex) {
109      // pass 
110    } catch (NoSuchElementException ex) {
111      // pass 
112    }
113  }
114
115  /**
116   * Makes sure that the LRU mapping is removed
117   *
118   * @see AbstractLRUMap#put(Object, Object)
119   */
120  @Test
121  public void testLRUMappingIsRemoved() {
122    int maxMappings = 4;
123    AbstractLRUMap<Integer, String> map =
124      createLRUMap(maxMappings);
125    assertEquals(0, map.size());
126
127    for (int i = 0; i < maxMappings; i++) {
128      map.put(i, String.valueOf(i));
129      assertEquals(i + 1, map.size());
130    }
131
132    assertTrue(map.containsKey(new Integer(0)));
133
134    map.put(maxMappings + 1,
135      String.valueOf(maxMappings + 1));
136
137    assertTrue(!map.containsKey(new Integer(0)));
138  }
139
140  /**
141   * Tests that getting an element from a map puts it at the end of
142   * the LRU queue.
143   *
144   * @see AbstractLRUMap#get(Object)
145   */
146  @Test
147  public void testGetFromMap() {
148    int maxMappings = 4;
149    AbstractLRUMap<Integer, String> map =
150      createLRUMap(maxMappings);
151    assertEquals(0, map.size());
152
153    for (int i = 0; i < maxMappings; i++) {
154      map.put(i, String.valueOf(i));
155      assertEquals(i + 1, map.size());
156    }
157
158    assertTrue(map.containsKey(new Integer(0)));
159    assertNotNull(map.get(new Integer(0)));
160
161    map.put(maxMappings + 1,
162      String.valueOf(maxMappings + 1));
163
164    assertTrue(!map.containsKey(new Integer(1)));
165  }
166
167  /**
168   * Tests getting an non-existent entry
169   *
170   * @see AbstractLRUMap#get(Object)
171   */
172  @Test
173  public void testGetNonExistent() {
174    int maxMappings = 4;
175    AbstractLRUMap map =
176      createLRUMap(maxMappings);
177    assertEquals(null, map.get("Test"));
178  }
179
180  /**
181   * Tests that removing and element doesn't effect the LRU order
182   *
183   * @see AbstractLRUMap#remove(Object)
184   */
185  @Test
186  public void testRemoveFromMap() {
187    int maxMappings = 4;
188    AbstractLRUMap<Integer, String> map =
189      createLRUMap(maxMappings);
190    assertEquals(0, map.size());
191
192    for (int i = 0; i < maxMappings; i++) {
193      map.put(i, String.valueOf(i));
194      assertEquals(i + 1, map.size());
195    }
196
197    assertTrue(map.containsKey(new Integer(0)));
198    assertNotNull(map.remove(new Integer(0)));
199
200    map.put(maxMappings + 1,
201      String.valueOf(maxMappings + 1));
202    assertTrue(map.containsKey(new Integer(1)));
203
204    map.put(maxMappings + 2,
205      String.valueOf(maxMappings + 2));
206
207    assertTrue(!map.containsKey(new Integer(1)));
208  }
209
210  /**
211   * Tests removing an non-existent entry
212   *
213   * @see AbstractLRUMap#remove(Object)
214   */
215  @Test
216  public void testRemoveNonExistent() {
217    int maxMappings = 4;
218    AbstractLRUMap map =
219      createLRUMap(maxMappings);
220    assertEquals(null, map.remove("Test"));
221  }
222
223  /**
224   * Tests clearing a map
225   *
226   * @see AbstractLRUMap#clear()
227   */
228  @Test
229  public void testClear() {
230    int maxMappings = 4;
231    AbstractLRUMap<Integer, String> map =
232      createLRUMap(maxMappings);
233    assertEquals(0, map.size());
234
235    for (int i = 0; i < maxMappings; i++) {
236      map.put(i, String.valueOf(i));
237      assertEquals(i + 1, map.size());
238    }
239
240    map.clear();
241    assertEquals(0, map.size());
242  }
243    /**                                                                                       
244     * An obscure and amusing edge case.  Parent's method signature throws no exception, so this
245     * method will accept any exception.                                                      
246     */                                                                                       
247    public void testNegativeSize()                                                            
248    {                                                                                         
249        try                                                                                   
250        {                                                                                     
251            createLRUMap( -1 );
252            fail( "Negative sizes should not be accepted" );                                  
253        }                                                                                     
254        catch( Exception e )  // we don't know what kind of exception the implementor will throw
255        {                                                                                     
256            // success                                                                        
257        }                                                                                     
258    }  
259
260    /**
261     * This will accept EITHER an exception being thrown, or the creation of map that never stores data.
262     */
263    public void testZeroSize()
264    {
265        AbstractLRUMap<Integer, String> zmap;
266        try
267        {
268            zmap = createLRUMap(0);
269        }
270        catch (Exception e)  // we don't know what kind of exception the implementor will throw
271        {
272            // success
273            return;
274        }
275        assertEquals( 0, zmap.size() );
276        zmap.put( 3, "Three" );
277        assertEquals(0, zmap.size());
278        assertNull( zmap.get( 3 ) );
279        assertEquals( 0, zmap.entrySet().size() );
280        assertNull( zmap.remove( 3 ) );
281
282    }
283
284    /*
285    I wrote this to make sure I matched the behavior of a regular map.
286    public void testRegMapCompare() {
287        HashMap<Integer, String> zmap;
288        zmap = new HashMap<Integer, String>(0);
289        assertEquals(0, zmap.size());
290        assertNull(zmap.get(3));
291        assertEquals(0, zmap.entrySet().size());
292        assertNull(zmap.remove(3));
293    }
294    */   
295
296}