From 4e83f52af85e7ad0a62b508c5721ddea9b5372a3 Mon Sep 17 00:00:00 2001 From: Ernest Date: Mon, 16 Feb 2026 15:14:22 +0300 Subject: [PATCH] Added RedisMap realization --- pom.xml | 6 + src/main/java/org/redis/Main.java | 20 ++- src/main/java/org/redis/RedisMap.java | 128 ++++++++++++++ src/test/java/org/redis/RedisMapTest.java | 200 ++++++++++++++++++++++ 4 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/redis/RedisMap.java create mode 100644 src/test/java/org/redis/RedisMapTest.java diff --git a/pom.xml b/pom.xml index b4c0aac..886d7ad 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,12 @@ 5.8.1 test + + org.mockito + mockito-core + 5.21.0 + test + \ No newline at end of file diff --git a/src/main/java/org/redis/Main.java b/src/main/java/org/redis/Main.java index 68b3db6..f90cd6f 100644 --- a/src/main/java/org/redis/Main.java +++ b/src/main/java/org/redis/Main.java @@ -1,7 +1,25 @@ package org.redis; +import redis.clients.jedis.Jedis; + +import java.util.Map; + public class Main { public static void main(String[] args) { - System.out.println("Hello world!"); + Map map = new RedisMap(new Jedis("localhost", 6379)); + + map.putAll(Map.of( + "User 1", "123", + "User 2", "456", + "User 3", "789" + )); + + System.out.println("KeySet: " + map.keySet()); + System.out.println("Values: " + map.values()); + System.out.println("Size: " + map.size()); + + map.clear(); + System.out.println("IsEmpty " + map.isEmpty()); + } } \ No newline at end of file diff --git a/src/main/java/org/redis/RedisMap.java b/src/main/java/org/redis/RedisMap.java new file mode 100644 index 0000000..c4d5332 --- /dev/null +++ b/src/main/java/org/redis/RedisMap.java @@ -0,0 +1,128 @@ +package org.redis; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; + +import java.util.*; + +public class RedisMap implements Map { + + private final Jedis jedis; + + public RedisMap(Jedis jedis) { + this.jedis = jedis; + } + + @Override + public int size() { + return Math.toIntExact(jedis.dbSize()); + } + + @Override + public boolean isEmpty() { + return jedis.dbSize() == 0; + } + + @Override + public boolean containsKey(Object key) { + if (key instanceof String keyStr) { + String value = jedis.get(keyStr); + return value != null; + } else { + throw new ClassCastException(); + } + } + + @Override + public boolean containsValue(Object value) { + if (value instanceof String valueStr) { + Collection values = this.values(); + for (String str : values) { + if (valueStr.equals(str)) return true; + } + return false; + }else { + throw new ClassCastException(); + } + } + + @Override + public String get(Object key) { + if (key instanceof String keyStr){ + return jedis.get(keyStr); + } else { + throw new ClassCastException(); + } + } + + @Override + public String put(String key, String value) { + String previousValue = jedis.get(key); + jedis.set(key, value); + return previousValue; + } + + @Override + public String remove(Object key) { + if (key instanceof String keyStr){ + String previousValue = jedis.get(keyStr); + jedis.del(keyStr); + return previousValue; + } else { + throw new ClassCastException(); + } + } + + @Override + public void putAll(Map m) { + if (m.isEmpty()) return; + String[] keysAndValues = new String[m.size() * 2]; + int i = 0; + for (Entry entry : m.entrySet()) { + keysAndValues[i++] = entry.getKey(); + keysAndValues[i++] = entry.getValue(); + } + jedis.mset(keysAndValues); + } + + @Override + public void clear() { + jedis.flushDB(); + } + + @Override + public Set keySet() { + return this.getKeySet(); + } + + @Override + public Collection values() { + return jedis.mget(this.getKeySet().toArray(new String[0])); + } + + @Override + public Set> entrySet() { + Set keySet = this.getKeySet(); + String[] keysArray = keySet.toArray(new String[0]); + List values = jedis.mget(keysArray); + + Set> entrySet = new HashSet<>(keySet.size()); + for (int i = 0; i < keysArray.length; i++) { + entrySet.add(new AbstractMap.SimpleEntry<>(keysArray[i], values.get(i))); + } + return entrySet; + } + + private Set getKeySet() { + Set keySet = new HashSet<>(); + ScanParams scanParams = new ScanParams().count(500); + String cursor = ScanParams.SCAN_POINTER_START; + do { + ScanResult scanResult = jedis.scan(cursor, scanParams); + keySet.addAll(scanResult.getResult()); + cursor = scanResult.getCursor(); + } while (!cursor.equals(ScanParams.SCAN_POINTER_START)); + return keySet; + } +} diff --git a/src/test/java/org/redis/RedisMapTest.java b/src/test/java/org/redis/RedisMapTest.java new file mode 100644 index 0000000..d888ddb --- /dev/null +++ b/src/test/java/org/redis/RedisMapTest.java @@ -0,0 +1,200 @@ +package org.redis; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; + +import java.util.*; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; + +class RedisMapTest { + + private Jedis jedisMock; + private RedisMap redisMap; + + @BeforeEach + void setUp() { + this.jedisMock = mock(Jedis.class); + this.redisMap = new RedisMap(jedisMock); + } + + @Test + void size() { + when(jedisMock.dbSize()).thenReturn(3L); + int size = redisMap.size(); + verify(jedisMock).dbSize(); + assertEquals(3, size); + } + + @Test + void isEmpty1() { + when(jedisMock.dbSize()).thenReturn(3L); + boolean isEmpty = redisMap.isEmpty(); + verify(jedisMock).dbSize(); + assertFalse(isEmpty); + } + + @Test + void isEmpty2() { + when(jedisMock.dbSize()).thenReturn(0L); + boolean isEmpty = redisMap.isEmpty(); + verify(jedisMock).dbSize(); + assertTrue(isEmpty); + } + + @Test + void containsKey() { + when(jedisMock.get("key 1")).thenReturn("value 1"); + boolean result = redisMap.containsKey("key 1"); + verify(jedisMock).get("key 1"); + assertTrue(result); + } + + @Test + void containsValue() { + ScanResult scanResult = mock(ScanResult.class); + when(scanResult.getResult()).thenReturn(List.of("key 1", "key 2", "key 3")); + when(scanResult.getCursor()).thenReturn("0"); + + when(jedisMock.scan(anyString(), any(ScanParams.class))) + .thenReturn(scanResult); + + when(jedisMock.mget(any(String[].class))) + .thenReturn(List.of("value 1", "value 2", "value 3")); + + boolean containsValue = redisMap.containsValue("value 2"); + verify(jedisMock).scan(anyString(), any(ScanParams.class)); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String[].class); + verify(jedisMock).mget(argumentCaptor.capture()); + String[] capturedKeys = argumentCaptor.getValue(); + assertEquals(3, capturedKeys.length); + assertEquals(Set.of("key 1", "key 2", "key 3"), new HashSet<>(Arrays.asList(capturedKeys))); + + assertTrue(containsValue); + } + + @Test + void get() { + when(jedisMock.get("Key 1")).thenReturn("Value 1"); + String result = redisMap.get("Key 1"); + verify(jedisMock).get("Key 1"); + assertEquals("Value 1", result); + } + + @Test + void put1() { + when(jedisMock.get("Key 1")).thenReturn(null); + String result = redisMap.put("Key 1", "Value 1"); + verify(jedisMock).get("Key 1"); + assertEquals(null, result); + } + + @Test + void put2() { + when(jedisMock.get("Key 1")).thenReturn("Value 1"); + String result = redisMap.put("Key 1", "Value 2"); + verify(jedisMock).get("Key 1"); + assertEquals("Value 1", result); + } + + @Test + void remove() { + when(jedisMock.get("Key 1")).thenReturn("Value 1"); + String result = redisMap.remove("Key 1"); + verify(jedisMock).del("Key 1"); + assertEquals("Value 1", result); + } + + @Test + void putAll() { + Map input = Map.of("Key 1", "Value 1", "Key 2", "Value 2", "Key 3", "Value 3"); + redisMap.putAll(input); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String[].class); + verify(jedisMock).mset(captor.capture()); + String[] kvArray = captor.getValue(); + + Map actual = new HashMap<>(); + for (int i = 0; i < kvArray.length; i += 2) { + actual.put(kvArray[i], kvArray[i + 1]); + } + assertEquals(input, actual); + } + + @Test + void clear() { + redisMap.clear(); + verify(jedisMock).flushDB(); + } + + @Test + void keySet() { + ScanResult scanResult = mock(ScanResult.class); + when(scanResult.getResult()).thenReturn(List.of("key1", "key2", "key3")); + when(scanResult.getCursor()).thenReturn("0"); + + when(jedisMock.scan(anyString(), any(ScanParams.class))) + .thenReturn(scanResult); + + Set keySet = redisMap.keySet(); + + verify(jedisMock).scan(anyString(), any(ScanParams.class)); + assertEquals(Set.of("key1", "key2", "key3"), keySet); + } + + @Test + void values() { + ScanResult scanResult = mock(ScanResult.class); + when(scanResult.getResult()).thenReturn(List.of("key1", "key2", "key3")); + when(scanResult.getCursor()).thenReturn("0"); + + when(jedisMock.scan(anyString(), any(ScanParams.class))) + .thenReturn(scanResult); + + when(jedisMock.mget("key1", "key2", "key3")) + .thenReturn(List.of("value1", "value2", "value3")); + + Collection values = redisMap.values(); + assertTrue(values.containsAll(List.of("value1", "value2", "value3"))); + + verify(jedisMock).scan(anyString(), any(ScanParams.class)); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + verify(jedisMock).mget(argumentCaptor.capture(), argumentCaptor.capture(), argumentCaptor.capture()); + List capturedKeys = argumentCaptor.getAllValues(); + assertTrue(capturedKeys.containsAll(List.of("key1", "key2", "key3"))); + } + + @Test + void entrySet() { + ScanResult scanResult = mock(ScanResult.class); + when(scanResult.getResult()).thenReturn(List.of("key1", "key2", "key3")); + when(scanResult.getCursor()).thenReturn("0"); + + when(jedisMock.scan(anyString(), any(ScanParams.class))) + .thenReturn(scanResult); + + when(jedisMock.mget("key1", "key2", "key3")) + .thenReturn(List.of("value1", "value2", "value3")); + + Set> entries = redisMap.entrySet(); + + assertEquals(3, entries.size()); + assertTrue(entries.contains(new AbstractMap.SimpleEntry<>("key1", "value1"))); + assertTrue(entries.contains(new AbstractMap.SimpleEntry<>("key2", "value2"))); + assertTrue(entries.contains(new AbstractMap.SimpleEntry<>("key3", "value3"))); + + verify(jedisMock).scan(anyString(), any(ScanParams.class)); + + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + verify(jedisMock).mget(argumentCaptor.capture(), argumentCaptor.capture(), argumentCaptor.capture()); + List capturedKeys = argumentCaptor.getAllValues(); + assertTrue(capturedKeys.containsAll(List.of("key1", "key2", "key3"))); + } +} \ No newline at end of file