diff --git a/modules/redis-it/src/test/scala/zio/redis/ListSpec.scala b/modules/redis-it/src/test/scala/zio/redis/ListSpec.scala index 014abbc11..fa6ecfd38 100644 --- a/modules/redis-it/src/test/scala/zio/redis/ListSpec.scala +++ b/modules/redis-it/src/test/scala/zio/redis/ListSpec.scala @@ -341,6 +341,14 @@ trait ListSpec extends IntegrationSpec { range <- redis.lRange(key, 0 to 1).returning[String] } yield assert(range)(equalTo(Chunk("hello", "world"))) }, + test("lRange elements by exclusive range") { + for { + redis <- ZIO.service[Redis] + key <- uuid + _ <- redis.lPush(key, "c", "b", "a") + range <- redis.lRange(key, 0 until 2).returning[String] + } yield assert(range)(equalTo(Chunk("a", "b"))) + }, test("lRange two elements negative indices") { for { redis <- ZIO.service[Redis] @@ -349,6 +357,14 @@ trait ListSpec extends IntegrationSpec { range <- redis.lRange(key, -2 to -1).returning[String] } yield assert(range)(equalTo(Chunk("hello", "world"))) }, + test("lRange elements by exclusive range with negative indices") { + for { + redis <- ZIO.service[Redis] + key <- uuid + _ <- redis.lPush(key, "d", "c", "b", "a") + range <- redis.lRange(key, -3 until -1).returning[String] + } yield assert(range)(equalTo(Chunk("b", "c"))) + }, test("lRange start out of bounds") { for { redis <- ZIO.service[Redis] diff --git a/modules/redis-it/src/test/scala/zio/redis/SortedSetsSpec.scala b/modules/redis-it/src/test/scala/zio/redis/SortedSetsSpec.scala index fcaaf9d11..5e1b72685 100644 --- a/modules/redis-it/src/test/scala/zio/redis/SortedSetsSpec.scala +++ b/modules/redis-it/src/test/scala/zio/redis/SortedSetsSpec.scala @@ -872,7 +872,7 @@ trait SortedSetsSpec extends IntegrationSpec { } yield assert(result.toList)(isEmpty)) ), suite("zRange")( - test("non-empty set") { + test("all members for non-empty set") { for { redis <- ZIO.service[Redis] key <- uuid @@ -891,6 +891,45 @@ trait SortedSetsSpec extends IntegrationSpec { ) ) }, + test("some members for non-empty set by inclusive range with negative bounds") { + for { + redis <- ZIO.service[Redis] + key <- uuid + delhi = MemberScore("Delhi", 1d) + mumbai = MemberScore("Mumbai", 2d) + london = MemberScore("London", 3d) + paris = MemberScore("Paris", 4d) + tokyo = MemberScore("Tokyo", 5d) + _ <- redis.zAdd(key)(delhi, mumbai, london, tokyo, paris) + result <- redis.zRange(key, -3 to -2).returning[String] + } yield assert(result.toList)(equalTo(List("London", "Paris"))) + }, + test("some members for non-empty set by inclusive range with positive bounds") { + for { + redis <- ZIO.service[Redis] + key <- uuid + delhi = MemberScore("Delhi", 1d) + mumbai = MemberScore("Mumbai", 2d) + london = MemberScore("London", 3d) + paris = MemberScore("Paris", 4d) + tokyo = MemberScore("Tokyo", 5d) + _ <- redis.zAdd(key)(delhi, mumbai, london, tokyo, paris) + result <- redis.zRange(key, 0 to 2).returning[String] + } yield assert(result.toList)(equalTo(List("Delhi", "Mumbai", "London"))) + }, + test("some members for non-empty set by exclusive range") { + for { + redis <- ZIO.service[Redis] + key <- uuid + delhi = MemberScore("Delhi", 1d) + mumbai = MemberScore("Mumbai", 2d) + london = MemberScore("London", 3d) + paris = MemberScore("Paris", 4d) + tokyo = MemberScore("Tokyo", 5d) + _ <- redis.zAdd(key)(delhi, mumbai, london, tokyo, paris) + result <- redis.zRange(key, 1 until -2).returning[String] + } yield assert(result.toList)(equalTo(List("Mumbai", "London"))) + }, test("empty set") { for { redis <- ZIO.service[Redis] diff --git a/modules/redis-it/src/test/scala/zio/redis/StringsSpec.scala b/modules/redis-it/src/test/scala/zio/redis/StringsSpec.scala index 59fc8c095..48ddd36b1 100644 --- a/modules/redis-it/src/test/scala/zio/redis/StringsSpec.scala +++ b/modules/redis-it/src/test/scala/zio/redis/StringsSpec.scala @@ -77,10 +77,18 @@ trait StringsSpec extends IntegrationSpec { for { redis <- ZIO.service[Redis] key <- uuid - _ <- redis.set(key, "value") + _ <- redis.set(key, "value") // "alu" => 01100001 01101100 01110101 count <- redis.bitCount(key, Some(1 to 3)) } yield assert(count)(equalTo(12L)) }, + test("over non-empty string with exclusive range") { + for { + redis <- ZIO.service[Redis] + key <- uuid + _ <- redis.set(key, "value") + count <- redis.bitCount(key, Some(1 until 4)) + } yield assert(count)(equalTo(12L)) + }, test("over non-empty string with range that is too large") { for { redis <- ZIO.service[Redis] @@ -1047,6 +1055,14 @@ trait StringsSpec extends IntegrationSpec { substr <- redis.getRange(key, 1 to 3).returning[String] } yield assert(substr)(isSome(equalTo("alu"))) }, + test("from non-empty string by exclusive range") { + for { + redis <- ZIO.service[Redis] + key <- uuid + _ <- redis.set(key, "value") + substr <- redis.getRange(key, 1 until 3).returning[String] + } yield assert(substr)(isSome(equalTo("al"))) + }, test("with range that exceeds non-empty string length") { for { redis <- ZIO.service[Redis] diff --git a/modules/redis/src/main/scala/zio/redis/Input.scala b/modules/redis/src/main/scala/zio/redis/Input.scala index fdbbcc116..5cde6684b 100644 --- a/modules/redis/src/main/scala/zio/redis/Input.scala +++ b/modules/redis/src/main/scala/zio/redis/Input.scala @@ -387,8 +387,10 @@ object Input { } case object RangeInput extends Input[Range] { - def encode(data: Range): RespCommand = - RespCommand(RespCommandArgument.Value(data.start.toString), RespCommandArgument.Value(data.end.toString)) + def encode(data: Range): RespCommand = { + val end = if (data.isInclusive) data.end else data.end - 1 + RespCommand(RespCommandArgument.Value(data.start.toString), RespCommandArgument.Value(end.toString)) + } } case object RankInput extends Input[Rank] { diff --git a/modules/redis/src/test/scala/zio/redis/InputSpec.scala b/modules/redis/src/test/scala/zio/redis/InputSpec.scala index 5c22006d5..d753f895f 100644 --- a/modules/redis/src/test/scala/zio/redis/InputSpec.scala +++ b/modules/redis/src/test/scala/zio/redis/InputSpec.scala @@ -649,23 +649,43 @@ object InputSpec extends BaseSpec { suite("Range")( test("with positive start and positive end") { for { - result <- ZIO.attempt(RangeInput.encode(Range(1, 5))) + result <- ZIO.attempt(RangeInput.encode(1 to 5)) } yield assert(result)(equalTo(RespCommand(Value("1"), Value("5")))) }, test("with negative start and positive end") { for { - result <- ZIO.attempt(RangeInput.encode(Range(-1, 5))) + result <- ZIO.attempt(RangeInput.encode(-1 to 5)) } yield assert(result)(equalTo(RespCommand(Value("-1"), Value("5")))) }, test("with positive start and negative end") { for { - result <- ZIO.attempt(RangeInput.encode(Range(1, -5))) + result <- ZIO.attempt(RangeInput.encode(1 to -5)) } yield assert(result)(equalTo(RespCommand(Value("1"), Value("-5")))) }, test("with negative start and negative end") { for { - result <- ZIO.attempt(RangeInput.encode(Range(-1, -5))) + result <- ZIO.attempt(RangeInput.encode(-1 to -5)) } yield assert(result)(equalTo(RespCommand(Value("-1"), Value("-5")))) + }, + test("with positive start and exclusive positive end") { + for { + result <- ZIO.attempt(RangeInput.encode(1 until 3)) + } yield assert(result)(equalTo(RespCommand(Value("1"), Value("2")))) + }, + test("with positive start and exclusive negative end") { + for { + result <- ZIO.attempt(RangeInput.encode(1 until -1)) + } yield assert(result)(equalTo(RespCommand(Value("1"), Value("-2")))) + }, + test("with negative start and exclusive positive end") { + for { + result <- ZIO.attempt(RangeInput.encode(-5 until 8)) + } yield assert(result)(equalTo(RespCommand(Value("-5"), Value("7")))) + }, + test("with negative start and exclusive negative end") { + for { + result <- ZIO.attempt(RangeInput.encode(-5 until -3)) + } yield assert(result)(equalTo(RespCommand(Value("-5"), Value("-4")))) } ), suite("Pattern")(