Skip to content

Commit c4e50ee

Browse files
committed
add negative cases
1 parent 8e1c59f commit c4e50ee

File tree

9 files changed

+159
-63
lines changed

9 files changed

+159
-63
lines changed

lib/src/main/java/com/github/tonivade/claudb/command/scan/HashScanCommand.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import static com.github.tonivade.claudb.data.DatabaseKey.safeKey;
88
import static com.github.tonivade.resp.protocol.RedisToken.array;
9+
import static com.github.tonivade.resp.protocol.RedisToken.error;
910
import static com.github.tonivade.resp.protocol.RedisToken.string;
1011
import static java.util.stream.Collectors.toList;
1112

@@ -29,7 +30,7 @@
2930
@ParamLength(2)
3031
@ParamType(DataType.HASH)
3132
public class HashScanCommand implements DBCommand {
32-
33+
3334
private final ScanParams params = new ScanParams(2);
3435

3536
@Override
@@ -38,17 +39,21 @@ public RedisToken execute(Database db, Request request) {
3839
int cursor = Integer.parseInt(request.getParam(1).toString());
3940
Map<SafeString, SafeString> value = db.getOrDefault(safeKey(key), DatabaseValue.EMPTY_HASH).getHash();
4041

41-
GlobPattern pattern = params.parsePattern(request);
42-
int count = params.parseCount(request);
42+
try {
43+
GlobPattern pattern = params.parsePattern(request);
44+
int count = params.parseCount(request);
4345

44-
List<RedisToken> result = value.entrySet().stream()
45-
.filter(entry -> pattern == null || pattern.match(entry.getKey().toString()))
46-
.skip(cursor).limit(count)
47-
.flatMap(entry -> Stream.of(string(entry.getKey()), string(entry.getValue())))
48-
.collect(toList());
49-
if (result.isEmpty()) {
50-
return array(string("0"), array());
46+
List<RedisToken> result = value.entrySet().stream()
47+
.filter(entry -> pattern == null || pattern.match(entry.getKey().toString()))
48+
.skip(cursor).limit(count)
49+
.flatMap(entry -> Stream.of(string(entry.getKey()), string(entry.getValue())))
50+
.collect(toList());
51+
if (result.isEmpty()) {
52+
return array(string("0"), array());
53+
}
54+
return array(string(String.valueOf(cursor + (result.size() / 2))), array(result));
55+
} catch (IllegalArgumentException e) {
56+
return error("ERR syntax error");
5157
}
52-
return array(string(String.valueOf(cursor + (result.size() / 2))), array(result));
5358
}
5459
}

lib/src/main/java/com/github/tonivade/claudb/command/scan/ScanCommand.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package com.github.tonivade.claudb.command.scan;
66

77
import static com.github.tonivade.resp.protocol.RedisToken.array;
8+
import static com.github.tonivade.resp.protocol.RedisToken.error;
89
import static com.github.tonivade.resp.protocol.RedisToken.string;
910
import static java.util.stream.Collectors.toList;
1011

@@ -21,25 +22,29 @@
2122
@Command("scan")
2223
@ParamLength(1)
2324
public class ScanCommand implements DBCommand {
24-
25+
2526
private final ScanParams params = new ScanParams(1);
2627

2728
@Override
2829
public RedisToken execute(Database db, Request request) {
2930
int cursor = Integer.parseInt(request.getParam(0).toString());
30-
31-
GlobPattern pattern = params.parsePattern(request);
32-
int count = params.parseCount(request);
33-
34-
List<RedisToken> result = db.entrySet().stream()
35-
.filter(entry -> pattern == null || pattern.match(entry.getKey().toString()))
36-
.skip(cursor).limit(count)
37-
.map(entry -> entry.getKey().getValue())
38-
.map(RedisToken::string)
39-
.collect(toList());
40-
if (result.isEmpty()) {
41-
return array(string("0"), array());
31+
32+
try {
33+
GlobPattern pattern = params.parsePattern(request);
34+
int count = params.parseCount(request);
35+
36+
List<RedisToken> result = db.entrySet().stream()
37+
.filter(entry -> pattern == null || pattern.match(entry.getKey().toString()))
38+
.skip(cursor).limit(count)
39+
.map(entry -> entry.getKey().getValue())
40+
.map(RedisToken::string)
41+
.collect(toList());
42+
if (result.isEmpty()) {
43+
return array(string("0"), array());
44+
}
45+
return array(string(String.valueOf(cursor + result.size())), array(result));
46+
} catch (IllegalArgumentException e) {
47+
return error("ERR syntax error");
4248
}
43-
return array(string(String.valueOf(cursor + result.size())), array(result));
4449
}
4550
}

lib/src/main/java/com/github/tonivade/claudb/command/scan/ScanParams.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,32 @@
88

99
import com.github.tonivade.claudb.glob.GlobPattern;
1010
import com.github.tonivade.resp.command.Request;
11+
import com.github.tonivade.resp.protocol.SafeString;
12+
import java.util.Optional;
1113

1214
class ScanParams {
1315

1416
private static final int DEFAULT_COUNT = 10;
1517
private static final String COUNT = "count";
1618
private static final String MATCH = "match";
17-
19+
1820
private final int skip;
1921

2022
ScanParams(int skip) {
2123
this.skip = checkPositive(skip);
2224
}
23-
25+
2426
int parseCount(Request request) {
2527
int count = DEFAULT_COUNT;
2628
for (int i = skip; i < request.getLength(); i++) {
2729
if (request.getParam(i).toString().equalsIgnoreCase(COUNT)) {
28-
count = request.getOptionalParam(++i).map(Object::toString).map(Integer::parseInt)
29-
.orElse(DEFAULT_COUNT);
30+
Optional<SafeString> optionalParam = request.getOptionalParam(++i);
31+
if (optionalParam.isPresent()) {
32+
count = optionalParam.map(Object::toString).map(Integer::parseInt)
33+
.orElse(DEFAULT_COUNT);
34+
} else {
35+
throw new IllegalArgumentException("syntax error");
36+
}
3037
}
3138
}
3239
return count;
@@ -36,8 +43,13 @@ GlobPattern parsePattern(Request request) {
3643
GlobPattern pattern = null;
3744
for (int i = skip; i < request.getLength(); i++) {
3845
if (request.getParam(i).toString().equalsIgnoreCase(MATCH)) {
39-
pattern = request.getOptionalParam(++i).map(Object::toString).map(GlobPattern::new)
40-
.orElse(null);
46+
Optional<SafeString> optionalParam = request.getOptionalParam(++i);
47+
if (optionalParam.isPresent()) {
48+
pattern = optionalParam.map(Object::toString).map(GlobPattern::new)
49+
.orElse(null);
50+
} else {
51+
throw new IllegalArgumentException("syntax error");
52+
}
4153
}
4254
}
4355
return pattern;

lib/src/main/java/com/github/tonivade/claudb/command/scan/SetScanCommand.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66

77
import static com.github.tonivade.claudb.data.DatabaseKey.safeKey;
88
import static com.github.tonivade.resp.protocol.RedisToken.array;
9+
import static com.github.tonivade.resp.protocol.RedisToken.error;
910
import static com.github.tonivade.resp.protocol.RedisToken.string;
1011
import static java.util.stream.Collectors.toList;
1112

12-
import java.util.List;
13-
import java.util.Set;
14-
1513
import com.github.tonivade.claudb.command.DBCommand;
1614
import com.github.tonivade.claudb.command.annotation.ParamType;
1715
import com.github.tonivade.claudb.data.DataType;
@@ -24,11 +22,14 @@
2422
import com.github.tonivade.resp.protocol.RedisToken;
2523
import com.github.tonivade.resp.protocol.SafeString;
2624

25+
import java.util.List;
26+
import java.util.Set;
27+
2728
@Command("sscan")
2829
@ParamLength(2)
2930
@ParamType(DataType.SET)
3031
public class SetScanCommand implements DBCommand {
31-
32+
3233
private final ScanParams params = new ScanParams(2);
3334

3435
@Override
@@ -37,17 +38,21 @@ public RedisToken execute(Database db, Request request) {
3738
int cursor = Integer.parseInt(request.getParam(1).toString());
3839
Set<SafeString> value = db.getOrDefault(safeKey(key), DatabaseValue.EMPTY_SET).getSet();
3940

40-
GlobPattern pattern = params.parsePattern(request);
41-
int count = params.parseCount(request);
41+
try {
42+
GlobPattern pattern = params.parsePattern(request);
43+
int count = params.parseCount(request);
4244

43-
List<RedisToken> result = value.stream()
44-
.filter(item -> pattern == null || pattern.match(item.toString()))
45-
.skip(cursor).limit(count)
46-
.map(RedisToken::string)
47-
.collect(toList());
48-
if (result.isEmpty()) {
49-
return array(string("0"), array());
45+
List<RedisToken> result = value.stream()
46+
.filter(item -> pattern == null || pattern.match(item.toString()))
47+
.skip(cursor).limit(count)
48+
.map(RedisToken::string)
49+
.collect(toList());
50+
if (result.isEmpty()) {
51+
return array(string("0"), array());
52+
}
53+
return array(string(String.valueOf(cursor + result.size())), array(result));
54+
} catch (IllegalArgumentException e) {
55+
return error("ERR syntax error");
5056
}
51-
return array(string(String.valueOf(cursor + result.size())), array(result));
5257
}
5358
}

lib/src/main/java/com/github/tonivade/claudb/command/scan/SortedSetScanCommand.java

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@
66

77
import static com.github.tonivade.claudb.data.DatabaseKey.safeKey;
88
import static com.github.tonivade.resp.protocol.RedisToken.array;
9+
import static com.github.tonivade.resp.protocol.RedisToken.error;
910
import static com.github.tonivade.resp.protocol.RedisToken.string;
1011
import static java.util.stream.Collectors.toList;
1112

12-
import java.util.List;
13-
import java.util.Map.Entry;
14-
import java.util.NavigableSet;
15-
import java.util.stream.Stream;
16-
1713
import com.github.tonivade.claudb.command.DBCommand;
1814
import com.github.tonivade.claudb.command.annotation.ParamType;
1915
import com.github.tonivade.claudb.data.DataType;
@@ -26,11 +22,16 @@
2622
import com.github.tonivade.resp.protocol.RedisToken;
2723
import com.github.tonivade.resp.protocol.SafeString;
2824

25+
import java.util.List;
26+
import java.util.Map.Entry;
27+
import java.util.NavigableSet;
28+
import java.util.stream.Stream;
29+
2930
@Command("zscan")
3031
@ParamLength(2)
3132
@ParamType(DataType.ZSET)
3233
public class SortedSetScanCommand implements DBCommand {
33-
34+
3435
private final ScanParams params = new ScanParams(2);
3536

3637
@Override
@@ -39,17 +40,21 @@ public RedisToken execute(Database db, Request request) {
3940
int cursor = Integer.parseInt(request.getParam(1).toString());
4041
NavigableSet<Entry<Double, SafeString>> value = db.getOrDefault(safeKey(key), DatabaseValue.EMPTY_ZSET).getSortedSet();
4142

42-
GlobPattern pattern = params.parsePattern(request);
43-
int count = params.parseCount(request);
44-
45-
List<RedisToken> result = value.stream()
46-
.filter(entry -> pattern == null || pattern.match(entry.getValue().toString()))
47-
.skip(cursor).limit(count)
48-
.flatMap(entry -> Stream.of(string(entry.getValue()), string(Double.toString(entry.getKey()))))
49-
.collect(toList());
50-
if (result.isEmpty()) {
51-
return array(string("0"), array());
43+
try {
44+
GlobPattern pattern = params.parsePattern(request);
45+
int count = params.parseCount(request);
46+
47+
List<RedisToken> result = value.stream()
48+
.filter(entry -> pattern == null || pattern.match(entry.getValue().toString()))
49+
.skip(cursor).limit(count)
50+
.flatMap(entry -> Stream.of(string(entry.getValue()), string(Double.toString(entry.getKey()))))
51+
.collect(toList());
52+
if (result.isEmpty()) {
53+
return array(string("0"), array());
54+
}
55+
return array(string(String.valueOf(cursor + (result.size() / 2))), array(result));
56+
} catch (IllegalArgumentException e) {
57+
return error("ERR syntax error");
5258
}
53-
return array(string(String.valueOf(cursor + (result.size() / 2))), array(result));
5459
}
5560
}

lib/src/test/java/com/github/tonivade/claudb/command/scan/HashScanCommandTest.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,23 @@ public void withCount() {
105105

106106
assertThat(cursor.getValue(), equalTo(safeString("2")));
107107
// unordered
108-
assertThat(result.getValue(), hasSize(2));
108+
assertThat(result.getValue(), hasSize(4));
109+
}
110+
111+
@Test
112+
public void missingMatchPattern() {
113+
rule
114+
.withParams("h", "0", "match")
115+
.execute()
116+
.assertThat(RedisToken.error("ERR syntax error"));
117+
}
118+
119+
@Test
120+
public void missingCountValue() {
121+
rule
122+
.withParams("h", "0", "count")
123+
.execute()
124+
.assertThat(RedisToken.error("ERR syntax error"));
109125
}
110126

111127
@Test

lib/src/test/java/com/github/tonivade/claudb/command/scan/ScanCommandTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,22 @@ public void withCount() {
9696
assertThat(result.getValue(), containsInAnyOrder(RedisToken.string("a"), RedisToken.string("ab")));
9797
}
9898

99+
@Test
100+
public void missingMatchPattern() {
101+
rule
102+
.withParams("0", "match")
103+
.execute()
104+
.assertThat(RedisToken.error("ERR syntax error"));
105+
}
106+
107+
@Test
108+
public void missingCountValue() {
109+
rule
110+
.withParams("0", "count")
111+
.execute()
112+
.assertThat(RedisToken.error("ERR syntax error"));
113+
}
114+
99115
@Test
100116
public void empty() {
101117
rule

lib/src/test/java/com/github/tonivade/claudb/command/scan/SetScanCommandTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,22 @@ public void withCount() {
9292
assertThat(result.getValue(), hasSize(2));
9393
}
9494

95+
@Test
96+
public void missingMatchPattern() {
97+
rule
98+
.withParams("s", "0", "match")
99+
.execute()
100+
.assertThat(RedisToken.error("ERR syntax error"));
101+
}
102+
103+
@Test
104+
public void missingCountValue() {
105+
rule
106+
.withParams("s", "0", "count")
107+
.execute()
108+
.assertThat(RedisToken.error("ERR syntax error"));
109+
}
110+
95111
@Test
96112
public void empty() {
97113
rule

lib/src/test/java/com/github/tonivade/claudb/command/scan/SortedSetScanCommandTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,22 @@ public void withCount() {
107107
string("2.0"), string("ab")));
108108
}
109109

110+
@Test
111+
public void missingMatchPattern() {
112+
rule
113+
.withParams("z", "0", "match")
114+
.execute()
115+
.assertThat(RedisToken.error("ERR syntax error"));
116+
}
117+
118+
@Test
119+
public void missingCountValue() {
120+
rule
121+
.withParams("z", "0", "count")
122+
.execute()
123+
.assertThat(RedisToken.error("ERR syntax error"));
124+
}
125+
110126
@Test
111127
public void empty() {
112128
rule

0 commit comments

Comments
 (0)