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 extends String, ? extends String> m) {
+ if (m.isEmpty()) return;
+ String[] keysAndValues = new String[m.size() * 2];
+ int i = 0;
+ for (Entry extends String, ? extends String> 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