, AutoCloseable {
+ private final JedisPool jedisPool;
+ private final Jedis jedis;
+
+ /**
+ * Constructs an RedisMap with the specified connection parameters.
+ * @param host - Redis database connection host.
+ * @param port - Redis database connection port.
+ * @throws NullPointerException - if host is null.
+ * @throws IllegalArgumentException – if host empty or port equals 0;
+ * */
+ public RedisMap(String host, int port) {
+ if (host == null) {
+ throw new NullPointerException("Host cannot be null");
+ }
+ if (host.isEmpty()) {
+ throw new IllegalArgumentException("Host is empty. Please set redis database connection host.");
+ }
+ if (port == 0) {
+ throw new IllegalArgumentException("The port is not specified. Please set redis database connection port.");
+ }
+ try {
+ this.jedisPool = new JedisPool(host, port);
+ this.jedis = jedisPool.getResource();
+ } catch (JedisConnectionException ex) {
+ throw new IllegalArgumentException("Invalid host or port value. Connection error: " + ex.getMessage());
+ }
+ }
+
+ /**
+ * Constructs an RedisMap with the specified connection parameters.
+ * @param jedisPool - pool of connections for Redis database.
+ * @throws NullPointerException - if host is null.
+ */
+ public RedisMap(JedisPool jedisPool) {
+ if (jedisPool == null) {
+ throw new NullPointerException("Jedis pool cannot be null");
+ }
+ try {
+ this.jedisPool = jedisPool;
+ this.jedis = jedisPool.getResource();
+ } catch (JedisConnectionException ex) {
+ throw new IllegalArgumentException("Invalid host or port value. Connection error: " + ex.getMessage());
+ }
+ }
+
+ /**
+ * Returns the number of key mappings in redis database.
+ * If the map contains more than Integer.MAX_VALUE elements, returns Integer.MAX_VALUE.
+ * For getting size in long format use {@link RedisMap#getSize()}
+ * @return the number of key mappings in redis database
+ */
+ @Override
+ public int size() {
+ final long size = getSize();
+ if (size > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
+ return (int) size;
+ }
+
+ /**
+ * Returns the number of key mappings in redis database.
+ * @return the number of key mappings in redis database
+ */
+ public long getSize() {
+ return jedis.dbSize();
+ }
+
+ /**
+ * Returns true if this map contains no key-value mappings.
+ * @return true if this map contains no key-value mappings
+ * */
+ @Override
+ public boolean isEmpty() {
+ return getSize() == 0L;
+ }
+
+ /**
+ * Returns true if this map contains a mapping for the specified key.
+ * More formally, returns true if and only if this map contains a mapping for a key k such that Objects.equals(key, k).
+ * (There can be at most one such mapping.)
+ * @param key – key whose presence in this map is to be tested
+ * @return true if this map contains a mapping for the specified key
+ * @throws ClassCastException – if the key's type not String.
+ * @throws NullPointerException – if the specified key is null.
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ if (key == null) {
+ throw new NullPointerException("Key cannot be null");
+ }
+ if (!(key instanceof String)) {
+ throw new ClassCastException("Key type must be String");
+ }
+ return jedis.exists((String) key);
+ }
+
+ /**
+ * Returns true if Redis maps one or more keys to the specified value.
+ * More formally, returns true if and only if Redis contains at least one mapping to a value v such that Objects.equals(value, v).
+ * @param value – value whose presence in this RedisMap is to be tested
+ * @return true if this RedisMap maps one or more keys to the specified value
+ * @throws ClassCastException – if the value is a not String type.
+ * @throws NullPointerException – if the specified value is null.
+ * */
+ @Override
+ public boolean containsValue(Object value) {
+ if (value == null) {
+ throw new NullPointerException("Key cannot be null");
+ }
+ if (!(value instanceof String)) {
+ throw new ClassCastException("Key type must be String");
+ }
+ for (String key : keySet()) {
+ String keyValue = jedis.get(key);
+ if (keyValue.equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
+ * @param key – the key whose associated value is to be returned
+ * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key
+ * @throws ClassCastException – if the key's type is not a string.
+ * @throws NullPointerException – if the specified key is null.
+ */
+ @Override
+ public String get(Object key) {
+ if (key == null) {
+ throw new NullPointerException("Key cannot be null");
+ }
+ if (!(key instanceof String)) {
+ throw new ClassCastException("Key type must be String");
+ }
+ return jedis.get((String) key);
+ }
+
+ /**
+ * Associates the specified value with the specified key in this map
+ * If the map previously contained a mapping for the key, the old value is replaced by the specified value.
+ * (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.)
+ * @param key – key with which the specified value is to be associated
+ * @param value – value to be associated with the specified key
+ * @return the previous value associated with key, or null if there was no mapping for key.
+ * @throws NullPointerException – if the specified key or value is null and this map does not permit null keys or values
+ * */
+ @Override
+ public String put(String key, String value) {
+ if (key == null || value == null) {
+ throw new NullPointerException("Key or value cannot be null");
+ }
+ String previousValue = get(key);
+ jedis.set(key, value);
+ return previousValue;
+ }
+
+ /**
+ * Removes the mapping for a key from this map if it is present.
+ * Returns the value to which this map previously associated the key,
+ * or {@code null} if the map contained no mapping for the key.
+ *
+ *
The map will not contain a mapping for the specified key once the
+ * call returns.
+ *
+ * @param key - key whose mapping is to be removed from the map
+ * @return the previous value associated with {@code key}, or
+ * {@code null} if there was no mapping for {@code key}.
+ * @throws ClassCastException if the key is of an inappropriate type for
+ * this map ({@linkplain Collection##optional-restrictions optional})
+ * @throws NullPointerException if the specified key is null and this
+ * map does not permit null keys ({@linkplain Collection##optional-restrictions optional})
+ */
+ @Override
+ public String remove(Object key) {
+ if (key == null) {
+ throw new NullPointerException("Key value cannot be null");
+ }
+ if (!(key instanceof String)) {
+ throw new ClassCastException("Key value must be string");
+ }
+ String deletedValue = get(key);
+ jedis.del((String) key);
+ return deletedValue;
+ }
+
+ /**
+ * Copies all the mappings from the specified map to redis.
+ * The effect of this call is equivalent to that of calling put(k, v) on this map once for each mapping from key k to value v in redis.
+ * The behavior of this operation is undefined if the specified map is modified while the operation is in progress.
+ * If the specified map has a defined encounter order, processing of its mappings generally occurs in that order.
+ * @param m – mappings to be stored in this map.
+ * @throws NullPointerException – if the specified map is null, or if this map does not permit null keys or values,
+ * and the specified map contains null keys or values.
+ * */
+ @Override
+ public void putAll(@NonNull Map extends String, ? extends String> m) {
+ if (m.containsKey(null) || m.containsValue(null)) {
+ throw new NullPointerException("Key value cannot be null");
+ }
+ for (String k : m.keySet()) {
+ jedis.set(k, m.get(k));
+ }
+ }
+
+ /**
+ * Removes all the mappings from this map.
+ * The map will be empty after this call returns.
+ */
+ @Override
+ public void clear() {
+ jedis.flushDB();
+ }
+
+ /**
+ * KeySet - is a snapshot of a collection of Redis keys.
+ * Changes to the RedisMap after calling KeySet() are not reflected in the set.
+ * Operations on a KeySet do not change the RedisMap.
+ * @return a set view of the keys contained in Redis.
+ */
+ @Override
+ @NonNull
+ public Set keySet() {
+ return jedis.keys("*");
+ }
+
+ /**
+ * Values - is a collection of the Redis mappings values.
+ * Changes to the RedisMap after calling values() are not reflected in the collection.
+ * Operations on values do not modify the values on Redis.
+ * @return - collection of the Redis mappings values.
+ * */
+ @Override
+ @NonNull
+ public Collection values() {
+ List values = new ArrayList<>();
+ for (String key : keySet()) {
+ values.add(get(key));
+ }
+ return values;
+ }
+
+ /**
+ * Returns a Set view of the mappings contained in Redis.
+ * The set is not fully supported by the RedisMap, but when the {@link Entry} method {@link Entry#setValue(String)} is called,
+ * the value for the entry key in the Entry and in the RedisMap is set.
+ * If set elements no changes to the Set, but changes to the map,
+ * when invokes {@link Entry} methods: {@link Entry#getKey()}, {@link Entry#getValue()}, {@link Entry#setValue(String)}
+ * then throws {@link IllegalStateException}.
+ * If the map is modified while an iteration over the set is in progress the results of the iteration are undefined.
+ * It does not support the add or addAll operations.
+ * @return a set view of the mappings contained in Redis
+ * */
+ @Override
+ @NonNull
+ public Set> entrySet() {
+ Set> entrySet = new HashSet<>();
+ for (String key : keySet()) {
+ Map.Entry entry = new Entry(key, RedisMap.this.get(key));
+ entrySet.add(entry);
+ }
+ return entrySet;
+ }
+
+ /**
+ * A RedisMap entry (key-value pair).
+ *
+ * Entry is not fully bound to RedisMap. When {@link Entry#setValue(String)} method is called,
+ * the value for the entry key is set in Entry and in RedisMap.
+ * If the RedisMap is modified and the key or value of the Entry is not valid for Redis,
+ * methods {@link Entry#getKey()}, {@link Entry#getValue()}, {@link Entry#setValue(String)} throw {@link IllegalStateException}.
+ * It is also undefined if the backing map has been modified after the Entry was
+ * returned by the iterator, except through the {@link Entry#setValue(String)} method.
+ *
+ * An Entry may also be obtained from a RedisMap's entry-set view by other means, for
+ * example, using the
+ * {@link Set#parallelStream parallelStream},
+ * {@link Set#stream stream},
+ * {@link Set#spliterator spliterator} methods,
+ * any of the
+ * {@link Set#toArray toArray} overloads,
+ * or by copying the entry-set view into another collection.
+ *
+ * @see RedisMap#entrySet()
+ */
+ final class Entry implements Map.Entry {
+ private final String key;
+ private String value;
+
+ public Entry(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Returns the key corresponding to this entry.
+ * @return the key corresponding to this entry
+ * @throws IllegalStateException if the entry has been removed from the RedisMap.
+ * */
+ @Override
+ public String getKey() {
+ if (!RedisMap.this.containsKey(key)) {
+ throw new IllegalStateException("Entry key not found in Redis");
+ }
+ return key;
+ }
+
+ /**
+ * Returns the value corresponding to this entry.
+ * If the mapping has been deleted from Redis, an IllegalStateException will be thrown.
+ * If the mapping value has been change in Redis, an IllegalStateException will be thrown.
+ * @return string value corresponding to this entry.
+ * @throws IllegalStateException if entry value not equals value in Redis for entry's key.
+ * */
+ @Override
+ public String getValue() {
+ String redisValue = RedisMap.this.get(key);
+ if (redisValue == null || !redisValue.equals(value)) {
+ throw new IllegalStateException("Entry value not actual value in Redis for key = " + key);
+ }
+ return value;
+ }
+
+ /**
+ * Replaces the value corresponding to this entry and the mapping's value Redis with the specified value.
+ * If the mapping has already been removed from Redis, the entry's key will be added with the new value and return null.
+ * @param value – new value to be stored in this entry and RedisMap.
+ * @return old value corresponding to the entry
+ * @throws NullPointerException – if new value is null.
+ * @throws IllegalStateException if entry value not equals value in Redis for entry's key.
+ */
+ @Override
+ public String setValue(String value) {
+ if (value == null) {
+ throw new NullPointerException("Entry value cannot be null");
+ }
+ String previousValue = getValue();
+ RedisMap.this.put(key, value);
+ this.value = value;
+ return previousValue;
+ }
+ }
+
+ @Override
+ public void close() {
+ jedis.close();
+ jedisPool.close();
+ }
+}
diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties
new file mode 100644
index 0000000..3b71844
--- /dev/null
+++ b/src/main/resources/log4j.properties
@@ -0,0 +1,4 @@
+log4j.rootLogger=INFO, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n
diff --git a/src/test/java/RedisMapTest.java b/src/test/java/RedisMapTest.java
new file mode 100644
index 0000000..e211155
--- /dev/null
+++ b/src/test/java/RedisMapTest.java
@@ -0,0 +1,546 @@
+import com.redis.testcontainers.RedisContainer;
+import org.junit.jupiter.api.*;
+import org.mockito.Mockito;
+import org.redis.RedisMap;
+import org.testcontainers.utility.DockerImageName;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Tests for RedisMap
+ * @author Alexei Shvariov
+ */
+public class RedisMapTest {
+ private static final RedisContainer REDIS = new RedisContainer(DockerImageName.parse("redis:6.2.6"));
+ private static JedisPool jedisPool;
+
+ private final JedisPool mockJedisPool = Mockito.mock(JedisPool.class);
+
+ @BeforeAll
+ public static void setUp() {
+ REDIS.start();
+ if (REDIS.isRunning()) {
+ jedisPool = new JedisPool(REDIS.getHost(), REDIS.getFirstMappedPort());
+ }
+
+
+ }
+
+ @BeforeEach
+ public void fillDatabase() {
+ Jedis jedis = jedisPool.getResource();
+ jedis.set("1", "one");
+ jedis.set("2", "two");
+ jedis.set("3", "three");
+ jedis.close();
+ }
+
+ @AfterEach
+ public void clearDatabase() {
+ Jedis jedis = jedisPool.getResource();
+ jedis.flushDB();
+ jedis.close();
+ }
+
+
+ @AfterAll
+ public static void closeResources() {
+ jedisPool.close();
+ REDIS.stop();
+ }
+
+
+
+ @Test
+ @DisplayName("Test constructor with port and host params when set valid connection params then return new RedisMap")
+ public void testConstructor_whenSetValidConnectionParam_thenReturnNewRedisMap() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertNotNull(redisMap);
+ }
+ }
+
+ @Test
+ @DisplayName("Test constructor with port and host params when host is null then throw nullPointerException")
+ public void testConstructor_whenHostIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(null, REDIS.getFirstMappedPort())) {
+ Assertions.assertNull(redisMap);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test constructor with port and host params when port = 0 then throw nullPointerException")
+ public void testConstructor_whenPortEquals0_thenThrowIllegalArgumentException() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), 0)) {
+ Assertions.assertNull(redisMap);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test constructor with port and host params when set not valid host then throw nullPointerException")
+ public void testConstructor_whenSetNotValidHost_thenThrowIllegalArgumentException() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ try (RedisMap redisMap = new RedisMap("notValidHost", REDIS.getFirstMappedPort())) {
+ Assertions.assertNull(redisMap);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test constructor with port and host params when set wrong port then throw nullPointerException")
+ public void testConstructor_whenSetWrongPort_thenThrowIllegalArgumentException() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort() + 9999)) {
+ Assertions.assertNull(redisMap);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test size when method called then return valid value")
+ public void testSize_whenMethodCalled_thenReturnValidValue() {
+ final int expectedSize = 3;
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertEquals(expectedSize, redisMap.size());
+ }
+ }
+
+ @Test
+ @DisplayName("Test getSize when method called then return valid value")
+ public void testGetSize_whenMethodCalled_thenReturnValidValue() {
+ final int expectedSize = 3;
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertEquals(expectedSize, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test isEmpty when Redis is not empty then return false")
+ public void testIsEmpty_whenRedisNotEmpty_thenReturnFalse() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertFalse(redisMap.isEmpty());
+ }
+ }
+
+ @Test
+ @DisplayName("Test isEmpty when Redis is empty then return true")
+ public void testIsEmpty_whenRedisIsEmpty_thenReturnTrue() {
+ Jedis jedis = jedisPool.getResource();
+ jedis.flushDB();
+ jedis.close();
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertTrue(redisMap.isEmpty());
+ }
+ }
+
+ @Test
+ @DisplayName("Test containsKey when key is contains in Redis then return true")
+ public void testContainsKey_whenKeyIsContainsInRedis_thenReturnTrue() {
+ String keyFromRedis = "2";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertTrue(redisMap.containsKey(keyFromRedis));
+ }
+ }
+
+ @Test
+ @DisplayName("Test containsKey when key is not contains in Redis then return false")
+ public void testContainsKey_whenKeyIsNotContainsInRedis_thenReturnFalse() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertFalse(redisMap.containsKey("unknown key"));
+ }
+ }
+
+ @Test
+ @DisplayName("Test containsKey when key is not string type then throw ClassCastException")
+ public void testContainsKey_whenKeyIsNotStringType_thenThrowClassCastException() {
+ Assertions.assertThrows(ClassCastException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.containsKey(55L);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test containsKey when key is null then throw NullPointerException")
+ public void testContainsKey_whenKeyIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.containsKey(null);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test containsValue when value contains in Redis then return true")
+ public void testContainsValue_whenValueContainsInRedis_thenReturnTrue() {
+ String valueFromRedis = "two";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertTrue(redisMap.containsValue(valueFromRedis));
+ }
+ }
+
+ @Test
+ @DisplayName("Test containsValue when value not contains in Redis then return false")
+ public void testContainsValue_whenValueNotContainsInRedis_thenReturnFalse() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertFalse(redisMap.containsValue("unknown value"));
+ }
+ }
+
+ @Test
+ @DisplayName("Test containsValue when value is not string type in Redis then throw ClassCastException")
+ public void testContainsValue_whenValueIsNotStringType_thenThrowClassCastException() {
+ Assertions.assertThrows(ClassCastException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.containsValue(55L);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test containsValue when value is null then throw NullPointerException")
+ public void testContainsValue_whenValueIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.containsValue(null);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test get when key is valid then return valid value")
+ public void testGet_whenKeyIsValid_thenReturnValidValue() {
+ String expectedValue = "three";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertEquals(expectedValue, redisMap.get("3"));
+ }
+ }
+
+ @Test
+ @DisplayName("Test get when key is not valid then return null")
+ public void testGet_whenKeyIsNotValid_thenReturnNull() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertNull(redisMap.get("unknown key"));
+ }
+ }
+
+ @Test
+ @DisplayName("Test get when key is null then throw NullPointerException")
+ public void testGet_whenKeyIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.get(null);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test get when key is not string then throw ClassCastException")
+ public void testGet_whenKeyIsNotString_thenThrowClassCastException() {
+ Assertions.assertThrows(ClassCastException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.get(777L);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test put when put new key and valid value then return null")
+ public void testPut_whenPutNewKeyAndValidValue_thenReturnNull() {
+ final int expectedSize = 4;
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertNull(redisMap.put("5", "five"));
+ Assertions.assertEquals(expectedSize, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test put when put available key and new value then return previous value")
+ public void testPut_whenPutAvailableKeyAndNewValue_thenReturnPreviousValue() {
+ final int expectedSize = 3;
+ final String previousValue = "two";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertEquals(previousValue,redisMap.put("2", "два"));
+ Assertions.assertEquals(expectedSize, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test put when put when key is null then throw NullPointerException")
+ public void testPut_whenKeyIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.put(null, "value");
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test put when put when value is null then throw NullPointerException")
+ public void testPut_whenValueIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.put("key", null);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test remove when Redis contains key then mapping success delete")
+ public void testRemove_whenRedisContainsKey_thenMappingSuccessDelete() {
+ final int expectedSize = 2;
+ final String expectedPreviousValue = "two";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertEquals(expectedPreviousValue,redisMap.remove("2"));
+ Assertions.assertEquals(expectedSize, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test remove when key missing in Redis then nothing will happen")
+ public void testRemove_whenKeyMissingInRedis_thenNothingWillHappen() {
+ final int expectedSize = 3;
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertNull(redisMap.remove("unknown key"));
+ Assertions.assertEquals(expectedSize, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test remove when key is null then throw NullPointerException")
+ public void testRemove_whenKeyIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.remove(null);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test remove when key is not string then throw ClassCastException")
+ public void testRemove_whenKeyIsNotString_thenThrowClassCastException() {
+ Assertions.assertThrows(ClassCastException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.remove(23L);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test putAll when collection being added is valid then collection is successfully added")
+ public void testPutAll_whenCollectionBeingAddedIsValid_thenCollectionIsSuccessfullyAdded() {
+ Map numbers = new HashMap<>();
+ numbers.put("4", "four");
+ numbers.put("5", "five");
+ numbers.put("6", "six");
+ final int expectedSize = 6;
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.putAll(numbers);
+ Assertions.assertEquals(expectedSize, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test putAll when collection is null then throw NullPointerException")
+ public void testPutAll_whenCollectionIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.putAll(null);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test putAll when collection's key is null then throw NullPointerException")
+ public void testPutAll_whenCollectionKeyIsNull_thenThrowNullPointerException() {
+ Map numbers = new HashMap<>();
+ numbers.put("4", "four");
+ numbers.put(null, "five");
+ numbers.put("6", "six");
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.putAll(numbers);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test putAll when collection's value is null then throw NullPointerException")
+ public void testPutAll_whenCollectionValueIsNull_thenThrowNullPointerException() {
+ Map numbers = new HashMap<>();
+ numbers.put("4", "four");
+ numbers.put("5", null);
+ numbers.put("6", "six");
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.putAll(numbers);
+ }
+ } );
+ }
+
+ @Test
+ @DisplayName("Test clear when invoke method then Redis successfully cleared")
+ public void testClear_whenInvokeMethod_thenRedisSuccessfullyCleared() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Assertions.assertTrue(redisMap.getSize() > 0);
+ redisMap.clear();
+ Assertions.assertEquals(0, redisMap.getSize());
+ }
+ }
+
+ @Test
+ @DisplayName("Test keySet when invoke method then return set of Redis keys")
+ public void testKeySet_whenInvokeMethod_thenReturnSetOfRedisKeys() {
+ final int expectedSize = 3;
+ final String keyFromRedis = "2";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Set keySet = redisMap.keySet();
+ Assertions.assertEquals(expectedSize, keySet.size());
+ Assertions.assertTrue(keySet.contains(keyFromRedis));
+ }
+ }
+
+ @Test
+ @DisplayName("Test values when invoke method then return collection of Redis values")
+ public void testValues_whenInvokeMethod_thenReturnCollectionOfValues() {
+ String valueFromRedis = "two";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Collection values = redisMap.values();
+ Assertions.assertFalse(values.isEmpty());
+ Assertions.assertTrue(values.contains(valueFromRedis));
+ }
+ }
+
+ @Test
+ @DisplayName("Test entrySet when invoke method then return set of entry")
+ public void testEntrySet_whenInvokeMethod_thenReturnSetOfEntry() {
+ final int expectedSize = 3;
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Set> entries = redisMap.entrySet();
+ Assertions.assertFalse(entries.isEmpty());
+ Assertions.assertEquals(expectedSize, entries.size());
+ }
+ }
+
+ @Test
+ @DisplayName("Test entry's method getKey when invoke method then return entry's key")
+ public void testEntryGetKey_whenRedisContainKey_thenReturnEntryKet() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ String key = redisMap.entrySet().stream().findAny().orElseThrow().getKey();
+ Assertions.assertNotNull(key);
+ Assertions.assertTrue(redisMap.containsKey(key));
+ }
+ }
+
+ @Test
+ @DisplayName("Test entry's method getKey when key not found in Redis then throw IllegalStateException")
+ public void testEntryGetKey_whenKeyNotFoundInRedis_thenThrowIllegalStateException() {
+ Assertions.assertThrows(IllegalStateException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.remove("1");
+ redisMap.remove("2");
+ Map.Entry entry = redisMap.entrySet().stream().findAny().orElseThrow();
+ redisMap.remove("3");
+ entry.getKey();
+ }
+ });
+ }
+
+ @Test
+ @DisplayName("Test entry's method getValue when Redis contain value then return entry's value")
+ public void testEntryGetValue_whenRedisContainValue_thenReturnEntryValue() {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ String value = redisMap.entrySet().stream().findAny().orElseThrow().getValue();
+ Assertions.assertNotNull(value);
+ Assertions.assertTrue(redisMap.containsValue(value));
+ }
+ }
+
+ @Test
+ @DisplayName("Test entry's method getValue when value not found in redis then throw IllegalStateException")
+ public void testEntryGetValue_whenValueNotFoundInRedis_thenThrowIllegalStateException() {
+ Assertions.assertThrows(IllegalStateException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ redisMap.remove("1");
+ redisMap.remove("2");
+ Map.Entry entry = redisMap.entrySet().stream().findAny().orElseThrow();
+ redisMap.remove("3");
+ entry.getValue();
+ }
+ });
+ }
+
+
+ @Test
+ @DisplayName("Test entry's method getValue when value has been changed in Redis then throw IllegalStateException")
+ public void testEntryGetValue_whenValueHasBeenChangedInRedis_thenThrowIllegalStateException() {
+ Assertions.assertThrows(IllegalStateException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Map.Entry entry = redisMap.entrySet().stream().findAny().orElseThrow();
+ redisMap.put("1", "один");
+ redisMap.put("2", "два");
+ redisMap.put("3", "три");
+ entry.getValue();
+ }
+ });
+ }
+
+ @Test
+ @DisplayName("Test entry's method setValue when Redis contain entry then return previous value")
+ public void testEntrySetValue_whenRedisContainEntry_thenReturnEntryValue() {
+ final String newValue = "newValue";
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Map.Entry entry = redisMap.entrySet().stream().findAny().orElseThrow();
+ Assertions.assertFalse(redisMap.containsValue(newValue));
+ Assertions.assertNotNull(entry.setValue(newValue));
+ Assertions.assertTrue(redisMap.containsValue(newValue));
+ }
+ }
+
+ @Test
+ @DisplayName("Test entry's method setValue when value is null then throw NullPointerException")
+ public void testEntrySetValue_whenValueIsNull_thenThrowNullPointerException() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Map.Entry entry = redisMap.entrySet().stream().findAny().orElseThrow();
+ entry.setValue(null);
+ }
+ });
+ }
+
+ @Test
+ @DisplayName("Test entry's method setValue when value has been changed in Redis then throw IllegalStateException")
+ public void testEntrySetValue_whenValueHasBeenChangedInRedis_thenThrowIllegalStateException() {
+ Assertions.assertThrows(IllegalStateException.class, () -> {
+ try (RedisMap redisMap = new RedisMap(REDIS.getHost(), REDIS.getFirstMappedPort())) {
+ Map.Entry entry = redisMap.entrySet().stream().findAny().orElseThrow();
+ redisMap.put("1", "один");
+ redisMap.put("2", "два");
+ redisMap.put("3", "три");
+ entry.setValue("New value");
+ }
+ });
+ }
+
+ @Test
+ @DisplayName("Test close when invoke method then JedisPool is closed")
+ public void testClose_whenInvokeMethod_thenJedisPoolClosed() {
+ when(mockJedisPool.getResource())
+ .thenReturn(jedisPool.getResource());
+ try(RedisMap redisMap = new RedisMap(mockJedisPool)) {
+ redisMap.getSize();
+ }
+ verify(mockJedisPool,times(1)).close();
+ }
+
+}