| Index: packages/quiver/test/collection/lru_map_test.dart
|
| diff --git a/packages/quiver/test/collection/lru_map_test.dart b/packages/quiver/test/collection/lru_map_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c4b478bfcfcd61e6048f07fe4ac500523fa8a013
|
| --- /dev/null
|
| +++ b/packages/quiver/test/collection/lru_map_test.dart
|
| @@ -0,0 +1,254 @@
|
| +// Copyright 2014 Google Inc. All Rights Reserved.
|
| +//
|
| +// Licensed under the Apache License, Version 2.0 (the "License");
|
| +// you may not use this file except in compliance with the License.
|
| +// You may obtain a copy of the License at
|
| +//
|
| +// http://www.apache.org/licenses/LICENSE-2.0
|
| +//
|
| +// Unless required by applicable law or agreed to in writing, software
|
| +// distributed under the License is distributed on an "AS IS" BASIS,
|
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +// See the License for the specific language governing permissions and
|
| +// limitations under the License.
|
| +
|
| +library quiver.collection.lru_map_test;
|
| +
|
| +import 'package:quiver/collection.dart';
|
| +import 'package:test/test.dart';
|
| +
|
| +void main() {
|
| + group('LruMap', () {
|
| + /// A map that will be initialize by individual tests.
|
| + LruMap<String, String> lruMap;
|
| +
|
| + test('the length property reflects how many keys are in the map', () {
|
| + lruMap = new LruMap();
|
| + expect(lruMap, hasLength(0));
|
| +
|
| + lruMap.addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| + expect(lruMap, hasLength(3));
|
| + });
|
| +
|
| + test('accessing keys causes them to be promoted', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.keys.toList(), ['C', 'B', 'A']);
|
| +
|
| + lruMap['B'];
|
| +
|
| + // In a LRU cache, the first key is the one that will be removed if the
|
| + // capacity is reached, so adding keys to the end is considered to be a
|
| + // 'promotion'.
|
| + expect(lruMap.keys.toList(), ['B', 'C', 'A']);
|
| + });
|
| +
|
| + test('new keys are added at the beginning', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + lruMap['D'] = 'Delta';
|
| + expect(lruMap.keys.toList(), ['D', 'C', 'B', 'A']);
|
| + });
|
| +
|
| + test('setting values on existing keys works, and promotes the key', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + lruMap['B'] = 'Bravo';
|
| + expect(lruMap.keys.toList(), ['B', 'C', 'A']);
|
| + expect(lruMap['B'], 'Bravo');
|
| + });
|
| +
|
| + test('the least recently used key is evicted when capacity hit', () {
|
| + lruMap = new LruMap(maximumSize: 3)..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + lruMap['D'] = 'Delta';
|
| + expect(lruMap.keys.toList(), ['D', 'C', 'B']);
|
| + });
|
| +
|
| + test('setting maximum size evicts keys until the size is met', () {
|
| + lruMap = new LruMap(maximumSize: 5)..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie',
|
| + 'D': 'Delta',
|
| + 'E': 'Epsilon'
|
| + });
|
| +
|
| + lruMap.maximumSize = 3;
|
| + expect(lruMap.keys.toList(), ['E', 'D', 'C']);
|
| + });
|
| +
|
| + test('accessing the `keys` collection does not affect position', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.keys.toList(), ['C', 'B', 'A']);
|
| +
|
| + lruMap.keys.forEach((_){});
|
| + lruMap.keys.forEach((_){});
|
| +
|
| + expect(lruMap.keys.toList(), ['C', 'B', 'A']);
|
| + });
|
| +
|
| + test('accessing the `values` collection does not affect position', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']);
|
| +
|
| + lruMap.values.forEach((_){});
|
| + lruMap.values.forEach((_){});
|
| +
|
| + expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']);
|
| + });
|
| +
|
| + test('clearing removes all keys and values', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.isNotEmpty, isTrue);
|
| + expect(lruMap.keys.isNotEmpty, isTrue);
|
| + expect(lruMap.values.isNotEmpty, isTrue);
|
| +
|
| + lruMap.clear();
|
| +
|
| + expect(lruMap.isEmpty, isTrue);
|
| + expect(lruMap.keys.isEmpty, isTrue);
|
| + expect(lruMap.values.isEmpty, isTrue);
|
| + });
|
| +
|
| + test('`containsKey` returns true if the key is in the map', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.containsKey('A'), isTrue);
|
| + expect(lruMap.containsKey('D'), isFalse);
|
| + });
|
| +
|
| + test('`containsValue` returns true if the value is in the map', () {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.containsValue('Alpha'), isTrue);
|
| + expect(lruMap.containsValue('Delta'), isFalse);
|
| + });
|
| +
|
| + test('`forEach` returns all key-value pairs without modifying order', () {
|
| + final keys = [];
|
| + final values = [];
|
| +
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| +
|
| + expect(lruMap.keys.toList(), ['C', 'B', 'A']);
|
| + expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']);
|
| +
|
| + lruMap.forEach((key, value) {
|
| + keys.add(key);
|
| + values.add(value);
|
| + });
|
| +
|
| + expect(keys, ['C', 'B', 'A']);
|
| + expect(values, ['Charlie', 'Beta', 'Alpha']);
|
| + expect(lruMap.keys.toList(), ['C', 'B', 'A']);
|
| + expect(lruMap.values.toList(), ['Charlie', 'Beta', 'Alpha']);
|
| + });
|
| +
|
| + group('`remove`', () {
|
| + setUp(() {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| + });
|
| +
|
| + test('returns the value associated with a key, if it exists', () {
|
| + expect(lruMap.remove('A'), 'Alpha');
|
| + });
|
| +
|
| + test('returns null if the provided key does not exist', () {
|
| + expect(lruMap.remove('D'), isNull);
|
| + });
|
| +
|
| + test('can remove the head', () {
|
| + lruMap.remove('C');
|
| + expect(lruMap.keys.toList(), ['B', 'A']);
|
| + });
|
| +
|
| + test('can remove the tail', () {
|
| + lruMap.remove('A');
|
| + expect(lruMap.keys.toList(), ['C', 'B']);
|
| + });
|
| +
|
| + test('can remove a middle entry', () {
|
| + lruMap.remove('B');
|
| + expect(lruMap.keys.toList(), ['C', 'A']);
|
| + });
|
| + });
|
| +
|
| + group('`putIfAbsent`', () {
|
| + setUp(() {
|
| + lruMap = new LruMap()..addAll({
|
| + 'A': 'Alpha',
|
| + 'B': 'Beta',
|
| + 'C': 'Charlie'
|
| + });
|
| + });
|
| +
|
| + test('adds an item if it does not exist, and moves it to the MRU', () {
|
| + expect(lruMap.putIfAbsent('D', () => 'Delta'), 'Delta');
|
| + expect(lruMap.keys.toList(), ['D', 'C', 'B', 'A']);
|
| + });
|
| +
|
| + test('does not add an item if it exists, but does promote it to MRU', () {
|
| + expect(lruMap.putIfAbsent('B', () => throw 'Oops!'), 'Beta');
|
| + expect(lruMap.keys.toList(), ['B', 'C', 'A']);
|
| + });
|
| +
|
| + test('removes the LRU item if `maximumSize` exceeded', () {
|
| + lruMap.maximumSize = 3;
|
| + expect(lruMap.putIfAbsent('D', () => 'Delta'), 'Delta');
|
| + expect(lruMap.keys.toList(), ['D', 'C', 'B']);
|
| + });
|
| + });
|
| + });
|
| +}
|
|
|