diff --git a/src/main/java/org/fungover/haze/Command.java b/src/main/java/org/fungover/haze/Command.java index 8fffbe13..767081af 100644 --- a/src/main/java/org/fungover/haze/Command.java +++ b/src/main/java/org/fungover/haze/Command.java @@ -1,6 +1,9 @@ package org.fungover.haze; public enum Command { - SET, GET, DEL, PING, SETNX, EXISTS, SAVE, RPUSH, LPUSH, LPOP, RPOP, LLEN, LMOVE, LTRIM, AUTH, LINDEX, INCR, DECR + + SET, GET, DEL, PING, SETNX, EXISTS, SAVE, RPUSH, LPUSH, LPOP, RPOP, LLEN, LMOVE, LTRIM, AUTH, LINDEX, INCR, DECR,LSET + + } diff --git a/src/main/java/org/fungover/haze/HazeList.java b/src/main/java/org/fungover/haze/HazeList.java index 41ded3ac..7f82c3d5 100644 --- a/src/main/java/org/fungover/haze/HazeList.java +++ b/src/main/java/org/fungover/haze/HazeList.java @@ -1,6 +1,7 @@ package org.fungover.haze; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; public class HazeList { @@ -297,4 +298,39 @@ private static String getKey(List inputList) { key = inputList.get(1); return key; } + + public String lSet(List inputlist){ + if (inputlist.size() < 4){ + return "-Err Wrong number of arguments for LSET\r\n"; + } + String key = getKey(inputlist); + + if (!hazeDatabase.containsKey(key)){ + return "-Err Key does not exist\r\n"; + } + int index; + if (inputlist.get(2).equals("-1")) { + + List list = getValueAsList(hazeDatabase.getValue(key)); + index = list.size() - 1; + } else { + try { + index = Integer.parseInt(inputlist.get(2)); + } catch (NumberFormatException e) { + return "-Err invalid index\r\n"; + } + } + String element = inputlist.get(3); + List list = getValueAsList(hazeDatabase.getValue(key)); + + if (index < 0 || index >= list.size()){ + return "-Err index out of bounds\r\n"; + } + List updatedList = IntStream.range(0, list.size()). + mapToObj(i -> i == index ? element : list.get(i)).toList(); + + hazeDatabase.addValue(key,listValueAsString(updatedList)); + return "+OK\r\n"; + + } } diff --git a/src/main/java/org/fungover/haze/Main.java b/src/main/java/org/fungover/haze/Main.java index f8314b54..e95a9930 100644 --- a/src/main/java/org/fungover/haze/Main.java +++ b/src/main/java/org/fungover/haze/Main.java @@ -121,6 +121,7 @@ public static String executeCommand(HazeDatabase hazeDatabase, List inpu case LMOVE -> hazeList.lMove(inputList); case LTRIM -> hazeList.callLtrim(inputList); case LINDEX -> hazeList.lIndex(inputList); + case LSET -> hazeList.lSet(inputList); case AUTH -> "+OK\r\n"; case INCR -> hazeDatabase.increaseValue(inputList); case DECR -> hazeDatabase.decreaseValue(inputList); diff --git a/src/test/java/org/fungover/haze/HazeListTest.java b/src/test/java/org/fungover/haze/HazeListTest.java index 99f958fd..40c817fe 100644 --- a/src/test/java/org/fungover/haze/HazeListTest.java +++ b/src/test/java/org/fungover/haze/HazeListTest.java @@ -1,9 +1,9 @@ package org.fungover.haze; import org.junit.jupiter.api.Test; import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; + class HazeListTest { @@ -15,21 +15,21 @@ class HazeListTest { void rPushWithTwoValuesShouldReturnTwo() { hazeList.rPush(List.of("", "key1", "value1")); String actual = hazeList.rPush(List.of("", "key1", "value2")); - assertEquals(":2\r\n",actual); + assertEquals(":2\r\n", actual); } @Test void lPushWithTwoValuesShouldReturnTwo() { hazeList.lPush(List.of("", "key1", "value1")); String actual = hazeList.lPush(List.of("", "key1", "value2")); - assertEquals(":2\r\n",actual); + assertEquals(":2\r\n", actual); } @Test void assertThatLPushWithMultipleValuesAddsInReverseOrder() { hazeList.lPush(List.of("", "key1", "value1", "value2")); String actual = hazeDatabase.getValue("key1"); - assertEquals("value2\r\nvalue1",actual); + assertEquals("value2\r\nvalue1", actual); } @Test @@ -37,14 +37,14 @@ void assertThatLPushMultipleTimesAddsInReverseOrder() { hazeList.lPush(List.of("", "key1", "value1")); hazeList.lPush(List.of("", "key1", "value2")); String actual = hazeDatabase.getValue("key1"); - assertEquals("value2\r\nvalue1",actual); + assertEquals("value2\r\nvalue1", actual); } @Test void assertThatRPushWithMultipleValuesAddsInCorrectOrder() { hazeList.rPush(List.of("", "key1", "value1", "value2")); String actual = hazeDatabase.getValue("key1"); - assertEquals("value1\r\nvalue2",actual); + assertEquals("value1\r\nvalue2", actual); } @Test @@ -52,12 +52,12 @@ void assertThatRPushMultipleTimesAddsInCorrectOrder() { hazeList.rPush(List.of("", "key1", "value1")); hazeList.rPush(List.of("", "key1", "value2")); String actual = hazeDatabase.getValue("key1"); - assertEquals("value1\r\nvalue2",actual); + assertEquals("value1\r\nvalue2", actual); } @Test void lPopShouldReturnNilStringWhenNoKeyIsPresent() { - String nilTest= hazeList.lPop("keyThatDontExist"); + String nilTest = hazeList.lPop("keyThatDontExist"); assertEquals("$5\r\n(nil)\r\n", nilTest); } @@ -69,15 +69,15 @@ void lPopShouldReturnCorrectValues() { } @Test - void lPopShouldReturnBulkStringWithSix(){ + void lPopShouldReturnBulkStringWithSix() { hazeList.rPush(List.of("", "key1", "value1", "value2")); String bulkStringSixChars = "$6\r\nvalue1\r\n"; assertEquals(bulkStringSixChars, hazeList.lPop("key1")); } @Test - void lPopWithoutKeyShouldReturnCorrectErrorText(){ - assertEquals("$5\r\n(nil)\r\n", hazeList.lPop("key1",1)); + void lPopWithoutKeyShouldReturnCorrectErrorText() { + assertEquals("$5\r\n(nil)\r\n", hazeList.lPop("key1", 1)); } @Test @@ -100,7 +100,7 @@ void rPopShouldReturnValue2RespString() { hazeList.rPush(List.of("", "key1", "value1", "value2")); String expected = "$6\r\nvalue2\r\n"; - assertEquals(expected, hazeList.rPop("key1" )); + assertEquals(expected, hazeList.rPop("key1")); } @Test @@ -112,7 +112,7 @@ void rPopShouldReturnValuesInReverseOrder() { } @Test - void rPopWithCountShouldReturnNilBulkStringWhenKeyIsMissing(){ + void rPopWithCountShouldReturnNilBulkStringWhenKeyIsMissing() { String nilFiveBulk = "$5\r\n(nil)\r\n"; assertEquals(nilFiveBulk, hazeList.rPop("noKey", 2)); } @@ -130,7 +130,7 @@ void alLenWithMissingKeyShouldReturRspZero() { } @Test - void lMoveShouldMoveVal1FromLeftToLeft(){ + void lMoveShouldMoveVal1FromLeftToLeft() { hazeList.rPush(List.of("", "key1", "val1", "val2")); hazeList.rPush(List.of("", "key2", "val3", "val4")); hazeList.lMove(List.of("", "key1", "key2", "LEFT", "LEFT")); @@ -147,7 +147,7 @@ void lMoveShouldMoveVal1FromLeftToLeft(){ } @Test - void lMoveShouldMoveVal1FromLeftToRight(){ + void lMoveShouldMoveVal1FromLeftToRight() { hazeList.rPush(List.of("", "key1", "val1", "val2")); hazeList.rPush(List.of("", "key2", "val3", "val4")); hazeList.lMove(List.of("", "key1", "key2", "LEFT", "RIGHT")); @@ -163,7 +163,7 @@ void lMoveShouldMoveVal1FromLeftToRight(){ } @Test - void lMoveShouldMoveValuesFromRightToLeft(){ + void lMoveShouldMoveValuesFromRightToLeft() { hazeList.rPush(List.of("", "key1", "val1", "val2")); hazeList.rPush(List.of("", "key2", "val3", "val4")); hazeList.lMove(List.of("", "key1", "key2", "RIGHT", "LEFT")); @@ -179,18 +179,18 @@ void lMoveShouldMoveValuesFromRightToLeft(){ } @Test - void lMoveShouldReturnCorrectErrorMessageWhenKeyIsMissing(){ + void lMoveShouldReturnCorrectErrorMessageWhenKeyIsMissing() { String errorText = "-One or both keys is missing.\r\n"; - assertEquals(errorText,hazeList.lMove(List.of("", "key1", "key2", "LEFT", "RIGHT"))); + assertEquals(errorText, hazeList.lMove(List.of("", "key1", "key2", "LEFT", "RIGHT"))); } @Test - void lMoveShouldReturnCorrectErrorMessageWhenListIsEmpty(){ + void lMoveShouldReturnCorrectErrorMessageWhenListIsEmpty() { hazeList.rPush(List.of("", "key1", "val1")); hazeList.rPush(List.of("", "key2", "val2")); hazeList.lMove(List.of("", "key1", "key2", "LEFT", "RIGHT")); String errorText = "-The source list is empty.\r\n"; - assertEquals(errorText,hazeList.lMove(List.of("", "key1", "key2", "LEFT", "RIGHT"))); + assertEquals(errorText, hazeList.lMove(List.of("", "key1", "key2", "LEFT", "RIGHT"))); } @Test @@ -214,7 +214,7 @@ void testLMoveInvalidFromAndTo() { @Test void correctValuesShouldStayAfterTrim() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); - hazeList.lTrim("key1", 1,2); + hazeList.lTrim("key1", 1, 2); String databaseCsv = hazeList.hazeDatabase.getValue("key1"); List list1 = HazeList.getValueAsList(databaseCsv); @@ -222,20 +222,20 @@ void correctValuesShouldStayAfterTrim() { } @Test - void lTrimShouldReturnErrorCorrectErrorTextWhenInputsAreOutOfRange(){ + void lTrimShouldReturnErrorCorrectErrorTextWhenInputsAreOutOfRange() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); String correctErrorText = "-The inputs are outside the range of the list.\r\n"; assertEquals(correctErrorText, hazeList.lTrim("key1", 2, 7)); } @Test - void lTrimShouldReturnCorrectErrorTextWhenKeyIsMissing(){ + void lTrimShouldReturnCorrectErrorTextWhenKeyIsMissing() { String correctErrorText = "-The key is not present in the database.\r\n"; assertEquals(correctErrorText, hazeList.lTrim("key1", 2, 7)); } @Test - void callLPopWithEmptyCountArrayShouldCallLopWithoutCount(){ + void callLPopWithEmptyCountArrayShouldCallLopWithoutCount() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3")); String result = hazeList.callLPop(List.of("", "key1")); String expected = "$4\r\nval1\r\n"; @@ -243,7 +243,7 @@ void callLPopWithEmptyCountArrayShouldCallLopWithoutCount(){ } @Test - void callLPopWithPopulatedArrayShouldCallLPopWithCount(){ + void callLPopWithPopulatedArrayShouldCallLPopWithCount() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3")); String result = hazeList.callLPop(List.of("", "key1", "2", "3")); String expected = "*2\r\n$4\r\nval1\r\n$4\r\nval2\r\n"; @@ -251,7 +251,7 @@ void callLPopWithPopulatedArrayShouldCallLPopWithCount(){ } @Test - void callRPopWithEmptyCountArrayShouldCallRopWithoutCount(){ + void callRPopWithEmptyCountArrayShouldCallRopWithoutCount() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3")); String result = hazeList.callRPop(List.of("", "key1")); String expected = "$4\r\nval3\r\n"; @@ -259,7 +259,7 @@ void callRPopWithEmptyCountArrayShouldCallRopWithoutCount(){ } @Test - void callLRopWithPopulatedArrayShouldCallRPopWithCount(){ + void callLRopWithPopulatedArrayShouldCallRPopWithCount() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3")); String result = hazeList.callRPop(List.of("", "key1", "2", "3")); String expected = "*2\r\n$4\r\nval3\r\n$4\r\nval2\r\n"; @@ -267,51 +267,89 @@ void callLRopWithPopulatedArrayShouldCallRPopWithCount(){ } @Test - void CallLtrimShouldCallLtrimWhenGivenAKeyAndTwoNummersAsArgument(){ + void CallLtrimShouldCallLtrimWhenGivenAKeyAndTwoNummersAsArgument() { hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); - String actual = hazeList.callLtrim(List.of("", "key1","2", "4")); + String actual = hazeList.callLtrim(List.of("", "key1", "2", "4")); assertEquals("+OK\r\n", actual); } @Test - void CallLReturnCorrectErrorMessageWhenIncorrectNumberOfArgumentsIsReceived () { + void CallLReturnCorrectErrorMessageWhenIncorrectNumberOfArgumentsIsReceived() { String expected = "-Wrong number of arguments for LTRIM\r\n"; assertEquals(expected, hazeList.callLtrim(List.of("", "key1"))); } @Test - void CallLReturnCorrectErrorMessageWhenNotGivenNumbersAsArguments () { + void CallLReturnCorrectErrorMessageWhenNotGivenNumbersAsArguments() { String expected = "-Value is not an integer or out of range\r\n"; assertEquals(expected, hazeList.callLtrim(List.of("", "key1", "horse", "Gunnar!"))); } @Test - void parserWithBadInputShouldReturnZero(){ + void parserWithBadInputShouldReturnZero() { assertEquals(0, HazeList.parser("This is not a number")); } + @Test + void lSetShouldUpdateValue() + { + hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); + hazeList.lSet(List.of("", "key1", "0", "hej")); + String asString = hazeDatabase.getValue("key1"); + assertThat(asString).isEqualTo("hej\r\nval2\r\nval3\r\nval4\r\nval5"); + } @Test - void callingLindexWithValidPositiveIndexReturnValue(){ - hazeList.rPush(List.of("", "key2", "val1", "val2", "val3")); - assertThat(hazeList.lIndex(List.of("", "key2", "2"))).isEqualTo("$4\r\nval3\r\n"); + void lSetWithIndexOutOfBoundsShouldReturnErrorMessage() { + hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); + assertThat(hazeList.lSet(List.of("", "key1", "6", "hej"))).isEqualTo("-Err index out of bounds\r\n"); } @Test - void callingLindexWithIndexOutOfBoundsReturnNil(){ - hazeList.rPush(List.of("", "key2", "val1", "val2", "val3")); - assertThat(hazeList.lIndex(List.of("", "key2", "3"))).isEqualTo("$5\r\n(nil)\r\n"); + void lSetWithNonExistingKey() { + hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); + assertThat(hazeList.lSet(List.of("", "key2", "3", "hej"))).isEqualTo("-Err Key does not exist\r\n"); + } + + @Test + void lSetIndexWithValidNegativeIndexReturnValue() { + hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); + hazeList.lSet(List.of("", "key1", "-1", "howdy")); + String asString = hazeDatabase.getValue("key1"); + assertThat(asString).isEqualTo("val1\r\nval2\r\nval3\r\nval4\r\nhowdy"); } @Test - void callingLindexWithValidNegativeIndexReturnValue(){ + void lSetNoKey() { + hazeList.rPush(List.of("", "", "val1", "val2", "val3")); + hazeList.lSet(List.of("", "", "0", "val1")); + String asString = hazeDatabase.getValue(""); + + assertThat(asString).isEqualTo("val1\r\nval2\r\nval3"); + } + + @Test + void lSetWithWrongNumberOFArguments() { + hazeList.rPush(List.of("", "key1", "val1")); + assertThat(hazeList.lSet(List.of("", "key1", "hej"))).isEqualTo("-Err Wrong number of arguments for LSET\r\n"); + } + + @Test + void lSetWithWrongIndex() { + hazeList.rPush(List.of("", "key1", "val1", "val2", "val3", "val4", "val5")); + assertThat(hazeList.lSet(List.of("", "key1", "-", "hej"))).isEqualTo("-Err invalid index\r\n"); +} + @Test + void callingLindexWithIndexOutOfBoundsReturnNil(){ hazeList.rPush(List.of("", "key2", "val1", "val2", "val3")); - assertThat(hazeList.lIndex(List.of("", "key2", "-1"))).isEqualTo("$4\r\nval3\r\n"); + assertThat(hazeList.lIndex(List.of("", "key2", "3"))).isEqualTo("$5\r\n(nil)\r\n"); } + @Test void callingLindexWithValidIndexZeroReturnFirstValue(){ hazeList.rPush(List.of("", "key2", "val1", "val2", "val3")); assertThat(hazeList.lIndex(List.of("", "key2", "0"))).isEqualTo("$4\r\nval1\r\n"); + } } diff --git a/src/test/java/org/fungover/haze/integration/HazeIT.java b/src/test/java/org/fungover/haze/integration/HazeIT.java index b27a893e..cc17e725 100644 --- a/src/test/java/org/fungover/haze/integration/HazeIT.java +++ b/src/test/java/org/fungover/haze/integration/HazeIT.java @@ -89,17 +89,25 @@ void listKeyWithMultipleValues() { pool.del("test"); assertThat(pool.exists("right")).isFalse(); } + @Test + void listLset(){ + pool.set("test","OK"); + assertThat(pool.lset("test", 0, "hej")).isEqualTo("OK"); + assertThat(pool.exists("test")).isTrue(); + pool.del("test"); + } + + @Test void lindexReturnCorrectIndex() { - assertThat(pool.rpush("test", "hello")).isEqualTo(1); + assertThat(pool.rpush("test", "hello")).isEqualTo(1) ; assertThat(pool.rpush("test", "hey")).isEqualTo(2); assertThat(pool.rpush("test", "bonjour")).isEqualTo(3); assertThat(pool.rpush("test", "hej")).isEqualTo(4); assertThat(pool.lindex("test", 0)).isEqualTo("hello"); assertThat(pool.lindex("test", -1)).isEqualTo("hej"); - pool.del("test"); assertThat(pool.exists("right")).isFalse(); }