Skip to content

Commit f99e7d3

Browse files
authored
setrange and incr tests (#298)
1 parent 758fb05 commit f99e7d3

File tree

6 files changed

+129
-8
lines changed

6 files changed

+129
-8
lines changed

.github/workflows/native-tests.yml

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jobs:
5252

5353
- name: Run native tests
5454
run: |
55+
./runtest --host 127.0.0.1 --port 39807 --single unit/type/incr
5556
./runtest --host 127.0.0.1 --port 39807 --single unit/type/hash
5657
./runtest --host 127.0.0.1 --port 39807 --single unit/type/list-2
5758
working-directory: native_tests/linux

native_tests/jm-test-server/src/main/java/com/github/fppt/jedismock/InterceptorMockServer.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.github.fppt.jedismock.datastructures.RMDataStructure;
44
import com.github.fppt.jedismock.datastructures.RMHash;
5+
import com.github.fppt.jedismock.datastructures.RMString;
56
import com.github.fppt.jedismock.datastructures.Slice;
67
import com.github.fppt.jedismock.operations.server.MockExecutor;
78
import com.github.fppt.jedismock.server.Response;
@@ -11,10 +12,13 @@
1112

1213
import java.io.IOException;
1314

15+
import static com.github.fppt.jedismock.Utils.convertToLong;
16+
1417
public final class InterceptorMockServer {
1518

1619
public static final int PORT = 39807;
1720
public static final Logger LOGGER = LoggerFactory.getLogger(InterceptorMockServer.class);
21+
public static final int SHARED_OBJECT_THRESHOLD = 10000;
1822

1923
private InterceptorMockServer() {
2024

@@ -39,11 +43,12 @@ public static void main(String[] args) throws IOException, InterruptedException
3943
if (value instanceof RMHash) {
4044
RMHash hash = (RMHash) value;
4145
return Response.bulkString(Slice.create(hash.getMeta()));
46+
} else if (value instanceof RMString) {
47+
return Response.bulkString(Slice.create(" at: "));
4248
}
4349
return Response.bulkString(
4450
Slice.create("DEBUG OBJECT command for this data structure is not yet supported")
4551
);
46-
4752
} else if ("object".equalsIgnoreCase(roName)
4853
&& "encoding".equalsIgnoreCase(params.get(0).toString())
4954
) {
@@ -59,7 +64,14 @@ public static void main(String[] args) throws IOException, InterruptedException
5964
return Response.bulkString(
6065
Slice.create("OBJECT ENCODING command for this data structure is not yet supported")
6166
);
62-
67+
} else if ("object".equalsIgnoreCase(roName)
68+
&& "refcount".equalsIgnoreCase(params.get(0).toString())
69+
) {
70+
//Imitate shared objects
71+
long val = convertToLong(state.base().getRMString(params.get(1)).getStoredDataAsString());
72+
if (val < SHARED_OBJECT_THRESHOLD) return
73+
Response.integer(2);
74+
else return Response.integer(1);
6375
} else {
6476
//Delegate execution to JedisMock which will mock the real Redis behaviour (when it can)
6577
return MockExecutor.proceed(state, roName, params);

src/main/java/com/github/fppt/jedismock/operations/hashes/HIncrByFloat.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class HIncrByFloat extends HIncrBy {
1818
super(base, params);
1919
}
2020

21-
private void validateHIncrByFloatArgument(Slice input) {
21+
private static void validateHIncrByFloatArgument(Slice input) {
2222

23-
final String errorMessage = "ERROR: HINCRBYFLOAT argument is not a float value";
23+
final String errorMessage = "ERR value is not a valid float";
2424

2525
// validate input is not started/ended with spaces
2626
String foundValueStr = String.valueOf(input);
@@ -30,8 +30,8 @@ private void validateHIncrByFloatArgument(Slice input) {
3030

3131
// validate input doesn't contain null-terminator symbols
3232
byte[] bts = input.data();
33-
for (int i = 0; i < bts.length; ++i) {
34-
if (bts[i] == 0) {
33+
for (byte bt : bts) {
34+
if (bt == 0) {
3535
throw new IllegalArgumentException(errorMessage);
3636
}
3737
}

src/main/java/com/github/fppt/jedismock/operations/strings/IncrOrDecrByFloat.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,29 @@ abstract class IncrOrDecrByFloat extends AbstractRedisOperation {
1414
super(base, params);
1515
}
1616

17+
private static BigDecimal toBigDecimal(String value) {
18+
if (value != null) {
19+
if (value.toLowerCase().endsWith("inf")) {
20+
throw new NumberFormatException("ERR increment would produce NaN or Infinity");
21+
} else try {
22+
return new BigDecimal(value);
23+
} catch (NumberFormatException e) {
24+
NumberFormatException modified = new NumberFormatException("ERR value is not a valid float");
25+
modified.initCause(e);
26+
throw modified;
27+
}
28+
} else {
29+
throw new NumberFormatException("ERR value is not a valid float");
30+
}
31+
}
32+
1733
protected Slice response() {
1834
Slice key = params().get(0);
19-
BigDecimal numericValue = new BigDecimal(params().get(1).toString());
35+
BigDecimal numericValue = toBigDecimal(params().get(1).toString());
2036

2137
RMString foundValue = base().getRMString(key);
2238
if (foundValue != null) {
23-
numericValue = numericValue.add(new BigDecimal(foundValue.getStoredDataAsString()));
39+
numericValue = numericValue.add(toBigDecimal(foundValue.getStoredDataAsString()));
2440
}
2541

2642
String data = String.valueOf(BigDecimal.valueOf(numericValue.intValue()).compareTo(numericValue) == 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.github.fppt.jedismock.operations.strings;
2+
3+
import com.github.fppt.jedismock.datastructures.RMString;
4+
import com.github.fppt.jedismock.datastructures.Slice;
5+
import com.github.fppt.jedismock.operations.AbstractRedisOperation;
6+
import com.github.fppt.jedismock.operations.RedisCommand;
7+
import com.github.fppt.jedismock.server.Response;
8+
import com.github.fppt.jedismock.storage.RedisBase;
9+
10+
import java.util.List;
11+
import java.util.Optional;
12+
13+
import static com.github.fppt.jedismock.Utils.convertToInteger;
14+
15+
@RedisCommand("setrange")
16+
public class SetRange extends AbstractRedisOperation {
17+
public SetRange(RedisBase base, List<Slice> params) {
18+
super(base, params);
19+
}
20+
21+
@Override
22+
protected Slice response() {
23+
Slice key = params().get(0);
24+
int offset = convertToInteger(params().get(1).toString());
25+
Slice value = params().get(2);
26+
String oldValue = Optional.ofNullable(base().getRMString(key))
27+
.map(RMString::getStoredDataAsString)
28+
.orElse("");
29+
String padding = "";
30+
if (offset > oldValue.length()) {
31+
padding = new String(new byte[offset - oldValue.length()]);
32+
}
33+
String newValue =
34+
oldValue.substring(0, Math.min(offset, oldValue.length()))
35+
+ padding
36+
+ value.toString();
37+
if (offset + value.length() < oldValue.length()) {
38+
newValue += oldValue.substring(offset + value.length());
39+
}
40+
base().putValue(key, Slice.create(newValue).extract(), null);
41+
return Response.integer(newValue.length());
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.github.fppt.jedismock.comparisontests.strings;
2+
3+
import com.github.fppt.jedismock.comparisontests.ComparisonBase;
4+
import org.junit.jupiter.api.BeforeEach;
5+
import org.junit.jupiter.api.TestTemplate;
6+
import org.junit.jupiter.api.extension.ExtendWith;
7+
import redis.clients.jedis.Jedis;
8+
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
11+
@ExtendWith(ComparisonBase.class)
12+
public class TestSetRange {
13+
@BeforeEach
14+
public void setUp(Jedis jedis) {
15+
jedis.flushAll();
16+
}
17+
18+
@TestTemplate
19+
public void setRange(Jedis jedis) {
20+
jedis.set("key1", "Hello World");
21+
final long l = jedis.setrange("key1", 6, "Redis");
22+
assertEquals(11, l);
23+
assertEquals("Hello Redis", jedis.get("key1"));
24+
}
25+
26+
@TestTemplate
27+
public void setRangeAppend(Jedis jedis) {
28+
jedis.set("key1", "Hello World");
29+
final long l = jedis.setrange("key1", 6, "Redis Redis");
30+
assertEquals(17, l);
31+
assertEquals("Hello Redis Redis", jedis.get("key1"));
32+
}
33+
34+
@TestTemplate
35+
public void setRangeInTheMiddle(Jedis jedis) {
36+
jedis.set("key1", "Hello World");
37+
final long l = jedis.setrange("key1", 2, "FOO");
38+
assertEquals(11, l);
39+
assertEquals("HeFOO World", jedis.get("key1"));
40+
}
41+
42+
43+
@TestTemplate
44+
public void setRangeZeroPadding(Jedis jedis) {
45+
final long l = jedis.setrange("key2", 6, "Redis");
46+
assertEquals(11, l);
47+
assertEquals(new String(new byte[6]) + "Redis", jedis.get("key2"));
48+
}
49+
}

0 commit comments

Comments
 (0)