├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── LICENSE
├── README.md
├── class diagram
└── cache-low-level-design.png
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── company
│ ├── Main.java
│ ├── algorithm
│ ├── DoublyLinkedList.java
│ ├── DoublyLinkedListNode.java
│ └── exception
│ │ └── InvalidElementException.java
│ └── cache
│ ├── Cache.java
│ ├── exception
│ ├── NotFoundException.java
│ └── StorageFullException.java
│ ├── factory
│ └── CacheFactory.java
│ ├── policies
│ ├── EvictionPolicy.java
│ └── LRUEvictionPolicy.java
│ └── storage
│ ├── HashMapBasedStorage.java
│ └── Storage.java
└── test
└── java
├── algorithm
└── DoublyLinkedListTest.java
└── cache
├── CacheTest.java
└── policies
└── LRUEvictionPolicyTest.java
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Java CI with Maven
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up JDK 9
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 9
23 | - name: Build with Maven
24 | run: mvn test --file pom.xml
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | *#
26 | *.iml
27 | *.ipr
28 | *.iws
29 | *.sw?
30 | *~
31 | .#*
32 | .*.md.html
33 | .DS_Store
34 | .classpath
35 | .gradle
36 | .idea
37 | .metadata
38 | .project
39 | .recommenders
40 | .settings
41 | /build
42 | /code
43 | MANIFEST.MF
44 | _site/
45 | activemq-data
46 | bin
47 | build
48 | build.log
49 | dependency-reduced-pom.xml
50 | dump.rdb
51 | interpolated*.xml
52 | lib/
53 | manifest.yml
54 | overridedb.*
55 | settings.xml
56 | target
57 | transaction-logs
58 | .flattened-pom.xml
59 | secrets.yml
60 | .gradletasknamecache
61 | .sts4-cache
62 |
63 | bin/
64 | tmp/
65 | *.tmp
66 | *.bak
67 | *.swp
68 | *~.nib
69 | local.properties
70 | .settings/
71 | .loadpath
72 |
73 | # External tool builders
74 | .externalToolBuilders/
75 |
76 | # Locally stored "Eclipse launch configurations"
77 | *.launch
78 |
79 | # PyDev specific (Python IDE for Eclipse)
80 | *.pydevproject
81 |
82 | # CDT-specific (C/C++ Development Tooling)
83 | .cproject
84 |
85 | # CDT- autotools
86 | .autotools
87 |
88 | # Java annotation processor (APT)
89 | .factorypath
90 |
91 | # PDT-specific (PHP Development Tools)
92 | .buildpath
93 |
94 | # sbteclipse plugin
95 | .target
96 |
97 | # Tern plugin
98 | .tern-project
99 |
100 | # TeXlipse plugin
101 | .texlipse
102 |
103 | # STS (Spring Tool Suite)
104 | .springBeans
105 |
106 | # Code Recommenders
107 | .recommenders/
108 |
109 | # Annotation Processing
110 | .apt_generated/
111 |
112 | # Scala IDE specific (Scala & Java development for Eclipse)
113 | .cache-main
114 | .scala_dependencies
115 | .worksheet
116 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Amar Prakash Pandey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cache - Low Level System Design
2 |
3 | ###### Class Diagram for low level system design of a cache
4 |
5 | 
6 |
7 | ### Problem Statement
8 |
9 | [Link](https://github.com/anomaly2104/cache-low-level-system-design/blob/master/problem-statement.md)
10 |
--------------------------------------------------------------------------------
/class diagram/cache-low-level-design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amarlearning/cache-low-level-design/9311238448462ee150624f59fe403e6753867033/class diagram/cache-low-level-design.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | groupId
8 | cache-low-level-design
9 | 1.0-SNAPSHOT
10 | jar
11 |
12 |
13 | UTF-8
14 | 9
15 | 9
16 |
17 |
18 |
19 |
20 | org.junit.jupiter
21 | junit-jupiter-engine
22 | 5.5.2
23 | test
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.apache.maven.plugins
31 | maven-surefire-plugin
32 | 2.22.0
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/main/java/com/company/Main.java:
--------------------------------------------------------------------------------
1 | package com.company;
2 |
3 | public class Main {
4 |
5 | public static void main(String[] args) {
6 | // write your code here
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/company/algorithm/DoublyLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.company.algorithm;
2 |
3 | import com.company.algorithm.exception.InvalidElementException;
4 |
5 | public class DoublyLinkedList {
6 |
7 | private DoublyLinkedListNode head;
8 | private DoublyLinkedListNode tail;
9 |
10 | public DoublyLinkedList() {
11 | this.head = new DoublyLinkedListNode<>(null);
12 | this.tail = new DoublyLinkedListNode<>(null);
13 |
14 | this.head.next = this.tail;
15 | this.tail.prev = this.head;
16 | }
17 |
18 | /**
19 | * Helper method is detach a node from {@DoubleLinkedList},
20 | * but the node may still be present in the memory.
21 | *
22 | * @param node
23 | */
24 | public void detachNode(DoublyLinkedListNode node) {
25 | // simply shifting the pointers
26 | if (node != null) {
27 | node.prev.next = node.next;
28 | node.next.prev = node.prev;
29 | }
30 | }
31 |
32 | /**
33 | * Helper method to add the input node as the last of the {@DoubleLinkedList}
34 | *
35 | * @param node
36 | */
37 | public void addNodeToLast(DoublyLinkedListNode node) {
38 | node.prev = this.tail.prev;
39 | this.tail.prev.next = node;
40 |
41 | node.next = this.tail;
42 | this.tail.prev = node;
43 | }
44 |
45 | /**
46 | * Helper method to add the element as the last node in this {@DoubleLinkedList}.
47 | *
48 | * @param element
49 | * @return DoubleLinkedList
50 | */
51 | public DoublyLinkedListNode addElementToLast(E element) {
52 | if (element == null) {
53 | throw new InvalidElementException("Null element cannot be added in list.");
54 | }
55 |
56 | DoublyLinkedListNode node = new DoublyLinkedListNode<>(element);
57 | this.addNodeToLast(node);
58 |
59 | return node;
60 | }
61 |
62 | /**
63 | * Helper method to check if this {@DoubleLinkedList} is empty.
64 | *
65 | * @return
66 | */
67 | public boolean isEmpty() {
68 | return this.head.next == tail;
69 | }
70 |
71 | /**
72 | * Method to get the first node in the {@DoubleLinkedList}
73 | *
74 | * @return
75 | */
76 | public DoublyLinkedListNode getFirstNode() {
77 | if (isEmpty())
78 | return null;
79 |
80 | return this.head.next;
81 | }
82 |
83 | /**
84 | * Method to get the last node in the {@DoubleLinkedList}
85 | *
86 | * @return
87 | */
88 | public DoublyLinkedListNode getLastNode() {
89 | if (isEmpty())
90 | return null;
91 |
92 | return this.tail.prev;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/company/algorithm/DoublyLinkedListNode.java:
--------------------------------------------------------------------------------
1 | package com.company.algorithm;
2 |
3 | /**
4 | * Node structure for the Doubly Linked List.
5 | *
6 | * @param Type Of Key
7 | */
8 | public class DoublyLinkedListNode {
9 |
10 | private final E element;
11 | DoublyLinkedListNode next;
12 | DoublyLinkedListNode prev;
13 |
14 | public DoublyLinkedListNode(E element) {
15 | this.element = element;
16 | this.next = null;
17 | this.prev = null;
18 | }
19 |
20 | public E getElement() {
21 | return element;
22 | }
23 |
24 | public DoublyLinkedListNode getNext() {
25 | return next;
26 | }
27 |
28 | public DoublyLinkedListNode getPrev() {
29 | return prev;
30 | }
31 | }
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/main/java/com/company/algorithm/exception/InvalidElementException.java:
--------------------------------------------------------------------------------
1 | package com.company.algorithm.exception;
2 |
3 | public class InvalidElementException extends RuntimeException {
4 |
5 | public InvalidElementException(final String message) {
6 | super(message);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/Cache.java:
--------------------------------------------------------------------------------
1 | package com.company.cache;
2 |
3 | import com.company.cache.exception.NotFoundException;
4 | import com.company.cache.exception.StorageFullException;
5 | import com.company.cache.policies.EvictionPolicy;
6 | import com.company.cache.storage.Storage;
7 |
8 | public class Cache {
9 |
10 | private final Storage storage;
11 | private final EvictionPolicy evictionPolicy;
12 |
13 | public Cache(Storage storage, EvictionPolicy evictionPolicy) {
14 | this.storage = storage;
15 | this.evictionPolicy = evictionPolicy;
16 | }
17 |
18 | public void put(K key, V value) {
19 | try {
20 | this.storage.put(key, value);
21 | this.evictionPolicy.keyAccessed(key);
22 | } catch (StorageFullException e) {
23 | K keyToRemove = this.evictionPolicy.removeKey();
24 | if (keyToRemove == null) {
25 | throw new RuntimeException("Unexpected state. Storage full and key is not evicting.");
26 | }
27 | this.storage.remove(keyToRemove);
28 | put(key, value);
29 | }
30 | }
31 |
32 | public V get(K key) {
33 | V value = null;
34 | try {
35 | value = this.storage.get(key);
36 | this.evictionPolicy.keyAccessed(key);
37 | } catch (NotFoundException e) {
38 | System.out.println("Key you are looking for, is not present in storage.");
39 | }
40 |
41 | return value;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/exception/NotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.exception;
2 |
3 | public class NotFoundException extends RuntimeException {
4 |
5 | public NotFoundException(final String message) {
6 | super(message);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/exception/StorageFullException.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.exception;
2 |
3 | public class StorageFullException extends RuntimeException {
4 |
5 | public StorageFullException(final String message) {
6 | super(message);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/factory/CacheFactory.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.factory;
2 |
3 | import com.company.cache.Cache;
4 | import com.company.cache.policies.LRUEvictionPolicy;
5 | import com.company.cache.storage.HashMapBasedStorage;
6 |
7 | public class CacheFactory {
8 | public Cache defaultCache(final int capacity) {
9 | return new Cache(new HashMapBasedStorage(capacity), new LRUEvictionPolicy());
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/policies/EvictionPolicy.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.policies;
2 |
3 |
4 | /**
5 | * Interface to define eviction policy.
6 | *
7 | * @param Type of Key.
8 | */
9 | public interface EvictionPolicy {
10 |
11 | /**
12 | * Add the key in the eviction policy.
13 | *
14 | * @param key
15 | */
16 | void keyAccessed(K key);
17 |
18 |
19 | /**
20 | * Remove the key from the eviction policy and return it.
21 | *
22 | * @return Type of Key.
23 | */
24 | K removeKey();
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/policies/LRUEvictionPolicy.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.policies;
2 |
3 | import com.company.algorithm.DoublyLinkedList;
4 | import com.company.algorithm.DoublyLinkedListNode;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | public class LRUEvictionPolicy implements EvictionPolicy {
10 |
11 | private final DoublyLinkedList dll;
12 | private final Map> nodeMap;
13 |
14 | public LRUEvictionPolicy() {
15 | this.nodeMap = new HashMap<>();
16 | this.dll = new DoublyLinkedList<>();
17 | }
18 |
19 | @Override
20 | public void keyAccessed(K key) {
21 | DoublyLinkedListNode node;
22 |
23 | if (nodeMap.containsKey(key)) {
24 | node = nodeMap.get(key);
25 | dll.detachNode(node);
26 | dll.addNodeToLast(node);
27 | } else {
28 | node = dll.addElementToLast(key);
29 | nodeMap.put(key, node);
30 | }
31 | }
32 |
33 | @Override
34 | public K removeKey() {
35 | DoublyLinkedListNode firstNode = dll.getFirstNode();
36 | if (firstNode == null) {
37 | return null;
38 | }
39 | dll.detachNode(firstNode);
40 | return firstNode.getElement();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/storage/HashMapBasedStorage.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.storage;
2 |
3 | import com.company.cache.exception.NotFoundException;
4 | import com.company.cache.exception.StorageFullException;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | public class HashMapBasedStorage implements Storage {
10 |
11 | private final Integer capacity;
12 | private final Map storage;
13 |
14 | public HashMapBasedStorage(Integer capacity) {
15 | this.capacity = capacity;
16 | this.storage = new HashMap<>();
17 | }
18 |
19 | @Override
20 | public void put(K key, V value) {
21 | if (isStorageFull()) throw new StorageFullException("Storage capacity is full.");
22 | this.storage.put(key, value);
23 | }
24 |
25 | @Override
26 | public void remove(K key) {
27 | if (!this.storage.containsKey(key)) throw new NotFoundException("No value cached with that key.");
28 | this.storage.remove(key);
29 | }
30 |
31 | @Override
32 | public V get(K key) {
33 | if (!this.storage.containsKey(key)) throw new NotFoundException("No value cached with that key.");
34 | return this.storage.get(key);
35 | }
36 |
37 | private boolean isStorageFull() {
38 | return this.storage.size() == capacity;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/company/cache/storage/Storage.java:
--------------------------------------------------------------------------------
1 | package com.company.cache.storage;
2 |
3 | import com.company.cache.exception.NotFoundException;
4 | import com.company.cache.exception.StorageFullException;
5 |
6 | /**
7 | * Interface used to manage storage of our application.
8 | *
9 | * @param Type of Key.
10 | * @param Type of Value.
11 | */
12 | public interface Storage {
13 |
14 | /**
15 | * Method used to add new cache in storage.
16 | *
17 | * @param key
18 | * @param value
19 | * @throws StorageFullException
20 | */
21 | void put(K key, V value);
22 |
23 | /**
24 | * Method used to remove an entry from the storage.
25 | *
26 | * @param key
27 | * @throws NotFoundException
28 | */
29 | void remove(K key);
30 |
31 | /**
32 | * Method used to get Value based on Key from storage.
33 | *
34 | * @param key
35 | * @return
36 | * @throws NotFoundException
37 | */
38 | V get(K key);
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/algorithm/DoublyLinkedListTest.java:
--------------------------------------------------------------------------------
1 | package algorithm;
2 |
3 | import com.company.algorithm.DoublyLinkedList;
4 | import com.company.algorithm.DoublyLinkedListNode;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import java.util.Collections;
9 | import java.util.List;
10 | import java.util.Optional;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 |
14 |
15 | class DoublyLinkedListTest {
16 |
17 | DoublyLinkedList dll;
18 |
19 | @BeforeEach
20 | void setup() {
21 | dll = new DoublyLinkedList<>();
22 | }
23 |
24 | @Test
25 | void test_doublyLinkedListAddNode() {
26 |
27 | // Given
28 | DoublyLinkedListNode node1 = new DoublyLinkedListNode<>(1);
29 | DoublyLinkedListNode node2 = new DoublyLinkedListNode<>(2);
30 | DoublyLinkedListNode node3 = new DoublyLinkedListNode<>(3);
31 | DoublyLinkedListNode node4 = new DoublyLinkedListNode<>(4);
32 |
33 | // When, then
34 | dll.addNodeToLast(node1);
35 | verifyDll(dll, Collections.unmodifiableList(List.of(1)));
36 |
37 | // When, then
38 | dll.addNodeToLast(node2);
39 | verifyDll(dll, Collections.unmodifiableList(List.of(1, 2)));
40 |
41 | // When, then
42 | dll.addNodeToLast(node3);
43 | verifyDll(dll, Collections.unmodifiableList(List.of(1, 2, 3)));
44 |
45 | // When, then
46 | dll.addNodeToLast(node4);
47 | verifyDll(dll, Collections.unmodifiableList(List.of(1, 2, 3, 4)));
48 | }
49 |
50 | @Test
51 | void test_doublyLinkedListDetachNode() {
52 |
53 | // Given
54 | DoublyLinkedListNode node1 = new DoublyLinkedListNode<>(1);
55 | DoublyLinkedListNode node2 = new DoublyLinkedListNode<>(2);
56 | DoublyLinkedListNode node3 = new DoublyLinkedListNode<>(3);
57 | DoublyLinkedListNode node4 = new DoublyLinkedListNode<>(4);
58 |
59 | dll.addNodeToLast(node1);
60 | dll.addNodeToLast(node2);
61 | dll.addNodeToLast(node3);
62 | dll.addNodeToLast(node4);
63 |
64 | // then
65 | verifyDll(dll, Collections.unmodifiableList(List.of(1, 2, 3, 4)));
66 |
67 | // when, then
68 | dll.detachNode(node1);
69 | verifyDll(dll, Collections.unmodifiableList(List.of(2, 3, 4)));
70 |
71 | // when, then
72 | dll.detachNode(node3);
73 | verifyDll(dll, Collections.unmodifiableList(List.of(2, 4)));
74 |
75 | // when, then
76 | dll.detachNode(null);
77 | verifyDll(dll, Collections.unmodifiableList(List.of(2, 4)));
78 |
79 | }
80 |
81 | private void verifyDll(DoublyLinkedList dll, List unmodifiableList) {
82 | assertEquals(dll.getFirstNode().getElement(), unmodifiableList.get(0));
83 | assertEquals(dll.getLastNode().getElement(), unmodifiableList.get(unmodifiableList.size() - 1));
84 |
85 | DoublyLinkedListNode currentNode = dll.getFirstNode();
86 |
87 | for (Integer element : unmodifiableList) {
88 | assertEquals(element, currentNode.getElement());
89 | currentNode = currentNode.getNext();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/test/java/cache/CacheTest.java:
--------------------------------------------------------------------------------
1 | package cache;
2 |
3 | import com.company.cache.Cache;
4 | import com.company.cache.factory.CacheFactory;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 | import static org.junit.jupiter.api.Assertions.assertNull;
10 |
11 | public class CacheTest {
12 |
13 | Cache cache;
14 |
15 | @BeforeEach
16 | public void setup() {
17 | cache = new CacheFactory().defaultCache(5);
18 | }
19 |
20 | @Test
21 | void test_itShouldBeAbleToGetItemsFromCache() {
22 | // When
23 | cache.put(1, 1);
24 | cache.put(2, 2);
25 | cache.put(3, 3);
26 |
27 | // Then
28 | assertEquals(1, cache.get(1));
29 | assertEquals(2, cache.get(2));
30 | assertEquals(3, cache.get(3));
31 |
32 | // When
33 | cache.put(4, 4);
34 | cache.put(5, 5);
35 |
36 | // Then
37 | assertEquals(4, cache.get(4));
38 | assertEquals(5, cache.get(5));
39 |
40 | // Since, we have used our cache to full capacity,
41 | // It will remove the last accessed element to insert new.
42 |
43 | // When
44 | cache.put(6, 6);
45 |
46 | // Then, Key 1 should be removed by now.
47 | assertNull(cache.get(1));
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/cache/policies/LRUEvictionPolicyTest.java:
--------------------------------------------------------------------------------
1 | package cache.policies;
2 |
3 | import com.company.cache.policies.LRUEvictionPolicy;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertEquals;
8 | import static org.junit.jupiter.api.Assertions.assertNull;
9 |
10 | class LRUEvictionPolicyTest {
11 |
12 | LRUEvictionPolicy evictionPolicy;
13 |
14 | @BeforeEach
15 | public void setup() {
16 | evictionPolicy = new LRUEvictionPolicy<>();
17 | }
18 |
19 | @Test
20 | void test_noKeysEvictionInitially() {
21 | // Then
22 | assertNull(evictionPolicy.removeKey());
23 | }
24 |
25 | @Test
26 | void test_keyEvictionInSameOrderTheyAreAccessed() {
27 |
28 | // When
29 | evictionPolicy.keyAccessed(1);
30 | evictionPolicy.keyAccessed(2);
31 | evictionPolicy.keyAccessed(3);
32 | evictionPolicy.keyAccessed(4);
33 | evictionPolicy.keyAccessed(5);
34 |
35 | // Then
36 | assertEquals(1, evictionPolicy.removeKey());
37 | assertEquals(2, evictionPolicy.removeKey());
38 | assertEquals(3, evictionPolicy.removeKey());
39 | assertEquals(4, evictionPolicy.removeKey());
40 | assertEquals(5, evictionPolicy.removeKey());
41 | }
42 |
43 | @Test
44 | void test_keyEvictionOrderIfReAccessed() {
45 |
46 | // When
47 | evictionPolicy.keyAccessed(1);
48 | evictionPolicy.keyAccessed(2);
49 | evictionPolicy.keyAccessed(3);
50 | evictionPolicy.keyAccessed(2);
51 | evictionPolicy.keyAccessed(1);
52 | evictionPolicy.keyAccessed(4);
53 | evictionPolicy.keyAccessed(5);
54 | evictionPolicy.keyAccessed(1);
55 |
56 | // Then
57 | assertEquals(3, evictionPolicy.removeKey());
58 | assertEquals(2, evictionPolicy.removeKey());
59 | assertEquals(4, evictionPolicy.removeKey());
60 | assertEquals(5, evictionPolicy.removeKey());
61 | assertEquals(1, evictionPolicy.removeKey());
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------