OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 Google Inc. All Rights Reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 library quiver.collection.lru_map_test; |
| 16 |
| 17 import 'package:quiver/collection.dart'; |
| 18 import 'package:test/test.dart'; |
| 19 |
| 20 void main() { |
| 21 group('LruMap', () { |
| 22 /// A map that will be initialize by individual tests. |
| 23 LruMap<String, String> lruMap; |
| 24 |
| 25 test('the length property reflects how many keys are in the map', () { |
| 26 lruMap = new LruMap(); |
| 27 expect(lruMap, hasLength(0)); |
| 28 |
| 29 lruMap.addAll({ |
| 30 'A': 'Alpha', |
| 31 'B': 'Beta', |
| 32 'C': 'Charlie' |
| 33 }); |
| 34 expect(lruMap, hasLength(3)); |
| 35 }); |
| 36 |
| 37 test('accessing keys causes them to be promoted', () { |
| 38 lruMap = new LruMap()..addAll({ |
| 39 'A': 'Alpha', |
| 40 'B': 'Beta', |
| 41 'C': 'Charlie' |
| 42 }); |
| 43 |
| 44 expect(lruMap.keys.toList(), ['C', 'B', 'A']); |
| 45 |
| 46 lruMap['B']; |
| 47 |
| 48 // In a LRU cache, the first key is the one that will be removed if the |
| 49 // capacity is reached, so adding keys to the end is considered to be a |
| 50 // 'promotion'. |
| 51 expect(lruMap.keys.toList(), ['B', 'C', 'A']); |
| 52 }); |
| 53 |
| 54 test('new keys are added at the beginning', () { |
| 55 lruMap = new LruMap()..addAll({ |
| 56 'A': 'Alpha', |
| 57 'B': 'Beta', |
| 58 'C': 'Charlie' |
| 59 }); |
| 60 |
| 61 lruMap['D'] = 'Delta'; |
| 62 expect(lruMap.keys.toList(), ['D', 'C', 'B', 'A']); |
| 63 }); |
| 64 |
| 65 test('setting values on existing keys works, and promotes the key', () { |
| 66 lruMap = new LruMap()..addAll({ |
| 67 'A': 'Alpha', |
| 68 'B': 'Beta', |
| 69 'C': 'Charlie' |
| 70 }); |
| 71 |
| 72 lruMap['B'] = 'Bravo'; |
| 73 expect(lruMap.keys.toList(), ['B', 'C', 'A']); |
| 74 expect(lruMap['B'], 'Bravo'); |
| 75 }); |
| 76 |
| 77 test('the least recently used key is evicted when capacity hit', () { |
| 78 lruMap = new LruMap(maximumSize: 3)..addAll({ |
| 79 'A': 'Alpha', |
| 80 'B': 'Beta', |
| 81 'C': 'Charlie' |
| 82 }); |
| 83 |
| 84 lruMap['D'] = 'Delta'; |
| 85 expect(lruMap.keys.toList(), ['D', 'C', 'B']); |
| 86 }); |
| 87 |
| 88 test('setting maximum size evicts keys until the size is met', () { |
| 89 lruMap = new LruMap(maximumSize: 5)..addAll({ |
| 90 'A': 'Alpha', |
| 91 'B': 'Beta', |
| 92 'C': 'Charlie', |
| 93 'D': 'Delta', |
| 94 'E': 'Epsilon' |
| 95 }); |
| 96 |
| 97 lruMap.maximumSize = 3; |
| 98 expect(lruMap.keys.toList(), ['E', 'D', 'C']); |
| 99 }); |
| 100 |
| 101 test('accessing the `keys` collection does not affect position', () { |
| 102 lruMap = new LruMap()..addAll({ |
| 103 'A': 'Alpha', |
| 104 'B': 'Beta', |
| 105 'C': 'Charlie' |
| 106 }); |
| 107 |
| 108 expect(lruMap.keys.toList(), ['C', 'B', 'A']); |
| 109 |
| 110 lruMap.keys.forEach((_){}); |
| 111 lruMap.keys.forEach((_){}); |
| 112 |
| 113 expect(lruMap.keys.toList(), ['C', 'B', 'A']); |
| 114 }); |
| 115 |
| 116 test('accessing the `values` collection does not affect position', () { |
| 117 lruMap = new LruMap()..addAll({ |
| 118 'A': 'Alpha', |
| 119 'B': 'Beta', |
| 120 'C': 'Charlie' |
| 121 }); |
| 122 |
| 123 expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']); |
| 124 |
| 125 lruMap.values.forEach((_){}); |
| 126 lruMap.values.forEach((_){}); |
| 127 |
| 128 expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']); |
| 129 }); |
| 130 |
| 131 test('clearing removes all keys and values', () { |
| 132 lruMap = new LruMap()..addAll({ |
| 133 'A': 'Alpha', |
| 134 'B': 'Beta', |
| 135 'C': 'Charlie' |
| 136 }); |
| 137 |
| 138 expect(lruMap.isNotEmpty, isTrue); |
| 139 expect(lruMap.keys.isNotEmpty, isTrue); |
| 140 expect(lruMap.values.isNotEmpty, isTrue); |
| 141 |
| 142 lruMap.clear(); |
| 143 |
| 144 expect(lruMap.isEmpty, isTrue); |
| 145 expect(lruMap.keys.isEmpty, isTrue); |
| 146 expect(lruMap.values.isEmpty, isTrue); |
| 147 }); |
| 148 |
| 149 test('`containsKey` returns true if the key is in the map', () { |
| 150 lruMap = new LruMap()..addAll({ |
| 151 'A': 'Alpha', |
| 152 'B': 'Beta', |
| 153 'C': 'Charlie' |
| 154 }); |
| 155 |
| 156 expect(lruMap.containsKey('A'), isTrue); |
| 157 expect(lruMap.containsKey('D'), isFalse); |
| 158 }); |
| 159 |
| 160 test('`containsValue` returns true if the value is in the map', () { |
| 161 lruMap = new LruMap()..addAll({ |
| 162 'A': 'Alpha', |
| 163 'B': 'Beta', |
| 164 'C': 'Charlie' |
| 165 }); |
| 166 |
| 167 expect(lruMap.containsValue('Alpha'), isTrue); |
| 168 expect(lruMap.containsValue('Delta'), isFalse); |
| 169 }); |
| 170 |
| 171 test('`forEach` returns all key-value pairs without modifying order', () { |
| 172 final keys = []; |
| 173 final values = []; |
| 174 |
| 175 lruMap = new LruMap()..addAll({ |
| 176 'A': 'Alpha', |
| 177 'B': 'Beta', |
| 178 'C': 'Charlie' |
| 179 }); |
| 180 |
| 181 expect(lruMap.keys.toList(), ['C', 'B', 'A']); |
| 182 expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']); |
| 183 |
| 184 lruMap.forEach((key, value) { |
| 185 keys.add(key); |
| 186 values.add(value); |
| 187 }); |
| 188 |
| 189 expect(keys, ['C', 'B', 'A']); |
| 190 expect(values, ['Charlie', 'Beta', 'Alpha']); |
| 191 expect(lruMap.keys.toList(), ['C', 'B', 'A']); |
| 192 expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']); |
| 193 }); |
| 194 |
| 195 group('`remove`', () { |
| 196 setUp(() { |
| 197 lruMap = new LruMap()..addAll({ |
| 198 'A': 'Alpha', |
| 199 'B': 'Beta', |
| 200 'C': 'Charlie' |
| 201 }); |
| 202 }); |
| 203 |
| 204 test('returns the value associated with a key, if it exists', () { |
| 205 expect(lruMap.remove('A'), 'Alpha'); |
| 206 }); |
| 207 |
| 208 test('returns null if the provided key does not exist', () { |
| 209 expect(lruMap.remove('D'), isNull); |
| 210 }); |
| 211 |
| 212 test('can remove the head', () { |
| 213 lruMap.remove('C'); |
| 214 expect(lruMap.keys.toList(), ['B', 'A']); |
| 215 }); |
| 216 |
| 217 test('can remove the tail', () { |
| 218 lruMap.remove('A'); |
| 219 expect(lruMap.keys.toList(), ['C', 'B']); |
| 220 }); |
| 221 |
| 222 test('can remove a middle entry', () { |
| 223 lruMap.remove('B'); |
| 224 expect(lruMap.keys.toList(), ['C', 'A']); |
| 225 }); |
| 226 }); |
| 227 |
| 228 group('`putIfAbsent`', () { |
| 229 setUp(() { |
| 230 lruMap = new LruMap()..addAll({ |
| 231 'A': 'Alpha', |
| 232 'B': 'Beta', |
| 233 'C': 'Charlie' |
| 234 }); |
| 235 }); |
| 236 |
| 237 test('adds an item if it does not exist, and moves it to the MRU', () { |
| 238 expect(lruMap.putIfAbsent('D', () => 'Delta'), 'Delta'); |
| 239 expect(lruMap.keys.toList(), ['D', 'C', 'B', 'A']); |
| 240 }); |
| 241 |
| 242 test('does not add an item if it exists, but does promote it to MRU', () { |
| 243 expect(lruMap.putIfAbsent('B', () => throw 'Oops!'), 'Beta'); |
| 244 expect(lruMap.keys.toList(), ['B', 'C', 'A']); |
| 245 }); |
| 246 |
| 247 test('removes the LRU item if `maximumSize` exceeded', () { |
| 248 lruMap.maximumSize = 3; |
| 249 expect(lruMap.putIfAbsent('D', () => 'Delta'), 'Delta'); |
| 250 expect(lruMap.keys.toList(), ['D', 'C', 'B']); |
| 251 }); |
| 252 }); |
| 253 }); |
| 254 } |
OLD | NEW |