1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.HashMap; 36 import java.util.Iterator; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.TreeSet; 41 import junit.framework.TestCase; 42 43 /** @author darick@google.com Darick Tong */ 44 public class SmallSortedMapTest extends TestCase { 45 // java.util.AbstractMap.SimpleEntry is private in JDK 1.5. We re-implement it 46 // here for JDK 1.5 users. 47 private static class SimpleEntry<K, V> implements Map.Entry<K, V> { 48 private final K key; 49 private V value; 50 SimpleEntry(K key, V value)51 SimpleEntry(K key, V value) { 52 this.key = key; 53 this.value = value; 54 } 55 56 @Override getKey()57 public K getKey() { 58 return key; 59 } 60 61 @Override getValue()62 public V getValue() { 63 return value; 64 } 65 66 @Override setValue(V value)67 public V setValue(V value) { 68 V oldValue = this.value; 69 this.value = value; 70 return oldValue; 71 } 72 eq(Object o1, Object o2)73 private static boolean eq(Object o1, Object o2) { 74 return o1 == null ? o2 == null : o1.equals(o2); 75 } 76 77 @Override equals(Object o)78 public boolean equals(Object o) { 79 if (!(o instanceof Map.Entry)) { 80 return false; 81 } 82 Map.Entry e = (Map.Entry) o; 83 return eq(key, e.getKey()) && eq(value, e.getValue()); 84 } 85 86 @Override hashCode()87 public int hashCode() { 88 return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode()); 89 } 90 } 91 testPutAndGetArrayEntriesOnly()92 public void testPutAndGetArrayEntriesOnly() { 93 runPutAndGetTest(3); 94 } 95 testPutAndGetOverflowEntries()96 public void testPutAndGetOverflowEntries() { 97 runPutAndGetTest(6); 98 } 99 runPutAndGetTest(int numElements)100 private void runPutAndGetTest(int numElements) { 101 // Test with even and odd arraySize 102 SmallSortedMap<Integer, Integer> map1 = SmallSortedMap.newInstanceForTest(3); 103 SmallSortedMap<Integer, Integer> map2 = SmallSortedMap.newInstanceForTest(4); 104 SmallSortedMap<Integer, Integer> map3 = SmallSortedMap.newInstanceForTest(3); 105 SmallSortedMap<Integer, Integer> map4 = SmallSortedMap.newInstanceForTest(4); 106 107 // Test with puts in ascending order. 108 for (int i = 0; i < numElements; i++) { 109 assertNull(map1.put(i, i + 1)); 110 assertNull(map2.put(i, i + 1)); 111 } 112 // Test with puts in descending order. 113 for (int i = numElements - 1; i >= 0; i--) { 114 assertNull(map3.put(i, i + 1)); 115 assertNull(map4.put(i, i + 1)); 116 } 117 118 assertEquals(Math.min(3, numElements), map1.getNumArrayEntries()); 119 assertEquals(Math.min(4, numElements), map2.getNumArrayEntries()); 120 assertEquals(Math.min(3, numElements), map3.getNumArrayEntries()); 121 assertEquals(Math.min(4, numElements), map4.getNumArrayEntries()); 122 123 List<SmallSortedMap<Integer, Integer>> allMaps = 124 new ArrayList<SmallSortedMap<Integer, Integer>>(); 125 allMaps.add(map1); 126 allMaps.add(map2); 127 allMaps.add(map3); 128 allMaps.add(map4); 129 130 for (SmallSortedMap<Integer, Integer> map : allMaps) { 131 assertEquals(numElements, map.size()); 132 for (int i = 0; i < numElements; i++) { 133 assertEquals(Integer.valueOf(i + 1), map.get(i)); 134 } 135 } 136 137 assertEquals(map1, map2); 138 assertEquals(map2, map3); 139 assertEquals(map3, map4); 140 } 141 testReplacingPut()142 public void testReplacingPut() { 143 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 144 for (int i = 0; i < 6; i++) { 145 assertNull(map.put(i, i + 1)); 146 assertNull(map.remove(i + 1)); 147 } 148 for (int i = 0; i < 6; i++) { 149 assertEquals(Integer.valueOf(i + 1), map.put(i, i + 2)); 150 } 151 } 152 testRemove()153 public void testRemove() { 154 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 155 for (int i = 0; i < 6; i++) { 156 assertNull(map.put(i, i + 1)); 157 assertNull(map.remove(i + 1)); 158 } 159 160 assertEquals(3, map.getNumArrayEntries()); 161 assertEquals(3, map.getNumOverflowEntries()); 162 assertEquals(6, map.size()); 163 assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet()); 164 165 assertEquals(Integer.valueOf(2), map.remove(1)); 166 assertEquals(3, map.getNumArrayEntries()); 167 assertEquals(2, map.getNumOverflowEntries()); 168 assertEquals(5, map.size()); 169 assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet()); 170 171 assertEquals(Integer.valueOf(5), map.remove(4)); 172 assertEquals(3, map.getNumArrayEntries()); 173 assertEquals(1, map.getNumOverflowEntries()); 174 assertEquals(4, map.size()); 175 assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet()); 176 177 assertEquals(Integer.valueOf(4), map.remove(3)); 178 assertEquals(3, map.getNumArrayEntries()); 179 assertEquals(0, map.getNumOverflowEntries()); 180 assertEquals(3, map.size()); 181 assertEquals(makeSortedKeySet(0, 2, 5), map.keySet()); 182 183 assertNull(map.remove(3)); 184 assertEquals(3, map.getNumArrayEntries()); 185 assertEquals(0, map.getNumOverflowEntries()); 186 assertEquals(3, map.size()); 187 188 assertEquals(Integer.valueOf(1), map.remove(0)); 189 assertEquals(2, map.getNumArrayEntries()); 190 assertEquals(0, map.getNumOverflowEntries()); 191 assertEquals(2, map.size()); 192 } 193 testClear()194 public void testClear() { 195 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 196 for (int i = 0; i < 6; i++) { 197 assertNull(map.put(i, i + 1)); 198 } 199 map.clear(); 200 assertEquals(0, map.getNumArrayEntries()); 201 assertEquals(0, map.getNumOverflowEntries()); 202 assertEquals(0, map.size()); 203 } 204 testGetArrayEntryAndOverflowEntries()205 public void testGetArrayEntryAndOverflowEntries() { 206 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 207 for (int i = 0; i < 6; i++) { 208 assertNull(map.put(i, i + 1)); 209 } 210 assertEquals(3, map.getNumArrayEntries()); 211 for (int i = 0; i < 3; i++) { 212 Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i); 213 assertEquals(Integer.valueOf(i), entry.getKey()); 214 assertEquals(Integer.valueOf(i + 1), entry.getValue()); 215 } 216 Iterator<Map.Entry<Integer, Integer>> it = map.getOverflowEntries().iterator(); 217 for (int i = 3; i < 6; i++) { 218 assertTrue(it.hasNext()); 219 Map.Entry<Integer, Integer> entry = it.next(); 220 assertEquals(Integer.valueOf(i), entry.getKey()); 221 assertEquals(Integer.valueOf(i + 1), entry.getValue()); 222 } 223 assertFalse(it.hasNext()); 224 } 225 testEntrySetContains()226 public void testEntrySetContains() { 227 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 228 for (int i = 0; i < 6; i++) { 229 assertNull(map.put(i, i + 1)); 230 } 231 Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); 232 for (int i = 0; i < 6; i++) { 233 assertTrue(entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1))); 234 assertFalse(entrySet.contains(new SimpleEntry<Integer, Integer>(i, i))); 235 } 236 } 237 testEntrySetAdd()238 public void testEntrySetAdd() { 239 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 240 Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); 241 for (int i = 0; i < 6; i++) { 242 Map.Entry<Integer, Integer> entry = new SimpleEntry<Integer, Integer>(i, i + 1); 243 assertTrue(entrySet.add(entry)); 244 assertFalse(entrySet.add(entry)); 245 } 246 for (int i = 0; i < 6; i++) { 247 assertEquals(Integer.valueOf(i + 1), map.get(i)); 248 } 249 assertEquals(3, map.getNumArrayEntries()); 250 assertEquals(3, map.getNumOverflowEntries()); 251 assertEquals(6, map.size()); 252 } 253 testEntrySetRemove()254 public void testEntrySetRemove() { 255 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 256 Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); 257 for (int i = 0; i < 6; i++) { 258 assertNull(map.put(i, i + 1)); 259 } 260 for (int i = 0; i < 6; i++) { 261 Map.Entry<Integer, Integer> entry = new SimpleEntry<Integer, Integer>(i, i + 1); 262 assertTrue(entrySet.remove(entry)); 263 assertFalse(entrySet.remove(entry)); 264 } 265 assertTrue(map.isEmpty()); 266 assertEquals(0, map.getNumArrayEntries()); 267 assertEquals(0, map.getNumOverflowEntries()); 268 assertEquals(0, map.size()); 269 } 270 testEntrySetClear()271 public void testEntrySetClear() { 272 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 273 for (int i = 0; i < 6; i++) { 274 assertNull(map.put(i, i + 1)); 275 } 276 map.clear(); 277 assertTrue(map.isEmpty()); 278 assertEquals(0, map.getNumArrayEntries()); 279 assertEquals(0, map.getNumOverflowEntries()); 280 assertEquals(0, map.size()); 281 } 282 testEntrySetIteratorNext()283 public void testEntrySetIteratorNext() { 284 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 285 for (int i = 0; i < 6; i++) { 286 assertNull(map.put(i, i + 1)); 287 } 288 Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); 289 for (int i = 0; i < 6; i++) { 290 assertTrue(it.hasNext()); 291 Map.Entry<Integer, Integer> entry = it.next(); 292 assertEquals(Integer.valueOf(i), entry.getKey()); 293 assertEquals(Integer.valueOf(i + 1), entry.getValue()); 294 } 295 assertFalse(it.hasNext()); 296 } 297 testEntrySetIteratorRemove()298 public void testEntrySetIteratorRemove() { 299 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 300 for (int i = 0; i < 6; i++) { 301 assertNull(map.put(i, i + 1)); 302 } 303 Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); 304 for (int i = 0; i < 6; i++) { 305 assertTrue(map.containsKey(i)); 306 it.next(); 307 it.remove(); 308 assertFalse(map.containsKey(i)); 309 assertEquals(6 - i - 1, map.size()); 310 } 311 } 312 testMapEntryModification()313 public void testMapEntryModification() { 314 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 315 for (int i = 0; i < 6; i++) { 316 assertNull(map.put(i, i + 1)); 317 } 318 Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); 319 for (int i = 0; i < 6; i++) { 320 Map.Entry<Integer, Integer> entry = it.next(); 321 entry.setValue(i + 23); 322 } 323 for (int i = 0; i < 6; i++) { 324 assertEquals(Integer.valueOf(i + 23), map.get(i)); 325 } 326 } 327 testMakeImmutable()328 public void testMakeImmutable() { 329 SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); 330 for (int i = 0; i < 6; i++) { 331 assertNull(map.put(i, i + 1)); 332 } 333 map.makeImmutable(); 334 assertEquals(Integer.valueOf(1), map.get(0)); 335 assertEquals(6, map.size()); 336 337 try { 338 map.put(23, 23); 339 fail("Expected UnsupportedOperationException"); 340 } catch (UnsupportedOperationException expected) { 341 } 342 343 Map<Integer, Integer> other = new HashMap<Integer, Integer>(); 344 other.put(23, 23); 345 try { 346 map.putAll(other); 347 fail("Expected UnsupportedOperationException"); 348 } catch (UnsupportedOperationException expected) { 349 } 350 351 try { 352 map.remove(0); 353 fail("Expected UnsupportedOperationException"); 354 } catch (UnsupportedOperationException expected) { 355 } 356 357 try { 358 map.clear(); 359 fail("Expected UnsupportedOperationException"); 360 } catch (UnsupportedOperationException expected) { 361 } 362 363 Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); 364 try { 365 entrySet.clear(); 366 fail("Expected UnsupportedOperationException"); 367 } catch (UnsupportedOperationException expected) { 368 } 369 370 Iterator<Map.Entry<Integer, Integer>> it = entrySet.iterator(); 371 while (it.hasNext()) { 372 Map.Entry<Integer, Integer> entry = it.next(); 373 try { 374 entry.setValue(0); 375 fail("Expected UnsupportedOperationException"); 376 } catch (UnsupportedOperationException expected) { 377 } 378 try { 379 it.remove(); 380 fail("Expected UnsupportedOperationException"); 381 } catch (UnsupportedOperationException expected) { 382 } 383 } 384 385 Set<Integer> keySet = map.keySet(); 386 try { 387 keySet.clear(); 388 fail("Expected UnsupportedOperationException"); 389 } catch (UnsupportedOperationException expected) { 390 } 391 392 Iterator<Integer> keys = keySet.iterator(); 393 while (keys.hasNext()) { 394 Integer key = keys.next(); 395 try { 396 keySet.remove(key); 397 fail("Expected UnsupportedOperationException"); 398 } catch (UnsupportedOperationException expected) { 399 } 400 try { 401 keys.remove(); 402 fail("Expected UnsupportedOperationException"); 403 } catch (UnsupportedOperationException expected) { 404 } 405 } 406 } 407 makeSortedKeySet(Integer... keys)408 private Set<Integer> makeSortedKeySet(Integer... keys) { 409 return new TreeSet<Integer>(Arrays.<Integer>asList(keys)); 410 } 411 } 412