diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 66b093954f..6cc9006f4f 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -3711,12 +3711,24 @@ public CompletableFuture lcs(@NonNull String key1, @NonNull String key2) return commandManager.submitNewCommand(LCS, arguments, this::handleStringResponse); } + @Override + public CompletableFuture lcs(@NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = new GlideString[] {key1, key2}; + return commandManager.submitNewCommand(LCS, arguments, this::handleGlideStringResponse); + } + @Override public CompletableFuture lcsLen(@NonNull String key1, @NonNull String key2) { String[] arguments = new String[] {key1, key2, LEN_REDIS_API}; return commandManager.submitNewCommand(LCS, arguments, this::handleLongResponse); } + @Override + public CompletableFuture lcsLen(@NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = new ArgsBuilder().add(key1).add(key2).add(LEN_REDIS_API).toArray(); + return commandManager.submitNewCommand(LCS, arguments, this::handleLongResponse); + } + @Override public CompletableFuture> lcsIdx(@NonNull String key1, @NonNull String key2) { String[] arguments = new String[] {key1, key2, IDX_COMMAND_STRING}; @@ -3724,6 +3736,16 @@ public CompletableFuture> lcsIdx(@NonNull String key1, @NonN LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); } + @Override + public CompletableFuture> lcsIdx( + @NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = + new ArgsBuilder().add(key1).add(key2).add(IDX_COMMAND_STRING).toArray(); + + return commandManager.submitNewCommand( + LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); + } + @Override public CompletableFuture> lcsIdx( @NonNull String key1, @NonNull String key2, long minMatchLen) { @@ -3735,6 +3757,21 @@ public CompletableFuture> lcsIdx( LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); } + @Override + public CompletableFuture> lcsIdx( + @NonNull GlideString key1, @NonNull GlideString key2, long minMatchLen) { + GlideString[] arguments = + new ArgsBuilder() + .add(key1) + .add(key2) + .add(IDX_COMMAND_STRING) + .add(MINMATCHLEN_COMMAND_STRING) + .add(minMatchLen) + .toArray(); + return commandManager.submitNewCommand( + LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); + } + @Override public CompletableFuture> lcsIdxWithMatchLen( @NonNull String key1, @NonNull String key2) { @@ -3742,6 +3779,19 @@ public CompletableFuture> lcsIdxWithMatchLen( return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); } + @Override + public CompletableFuture> lcsIdxWithMatchLen( + @NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = + new ArgsBuilder() + .add(key1) + .add(key2) + .add(IDX_COMMAND_STRING) + .add(WITHMATCHLEN_COMMAND_STRING) + .toArray(); + return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); + } + @Override public CompletableFuture> lcsIdxWithMatchLen( @NonNull String key1, @NonNull String key2, long minMatchLen) { @@ -3758,6 +3808,22 @@ public CompletableFuture> lcsIdxWithMatchLen( return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); } + @Override + public CompletableFuture> lcsIdxWithMatchLen( + @NonNull GlideString key1, @NonNull GlideString key2, long minMatchLen) { + GlideString[] arguments = + new ArgsBuilder() + .add(key1) + .add(key2) + .add(IDX_COMMAND_STRING) + .add(MINMATCHLEN_COMMAND_STRING) + .add(minMatchLen) + .add(WITHMATCHLEN_COMMAND_STRING) + .toArray(); + + return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); + } + @Override public CompletableFuture publish(@NonNull String channel, @NonNull String message) { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/StringBaseCommands.java b/java/client/src/main/java/glide/api/commands/StringBaseCommands.java index 4767417d1a..151b5e909b 100644 --- a/java/client/src/main/java/glide/api/commands/StringBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StringBaseCommands.java @@ -662,6 +662,28 @@ public interface StringBaseCommands { */ CompletableFuture lcs(String key1, String key2); + /** + * Returns the longest common subsequence between strings stored at key1 and + * key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return A String containing the longest common subsequence between the 2 strings. + * An empty String is returned if the keys do not exist or have no common + * subsequences. + * @example + *
{@code
+     * // testKey1 = abcd, testKey2 = axcd
+     * GlideString result = client.lcs(gs("testKey1"), gs("testKey2")).get();
+     * assert result.equals(gs("acd"));
+     * }
+ */ + CompletableFuture lcs(GlideString key1, GlideString key2); + /** * Returns the length of the longest common subsequence between strings stored at key1 * and key2. @@ -682,6 +704,26 @@ public interface StringBaseCommands { */ CompletableFuture lcsLen(String key1, String key2); + /** + * Returns the length of the longest common subsequence between strings stored at key1 + * and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return The length of the longest common subsequence between the 2 strings. + * @example + *
{@code
+     * // testKey1 = abcd, testKey2 = axcd
+     * Long result = client.lcsLen(gs("testKey1"), gs("testKey2")).get();
+     * assert result.equals(3L);
+     * }
+ */ + CompletableFuture lcsLen(GlideString key1, GlideString key2); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -725,6 +767,49 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdx(String key1, String key2); + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd123") and key2 + * holds the GlideString gs("bcdef123") then the sample result would be + *
{@code
+     * new Long[][][] {
+     *      {
+     *          {4L, 6L},
+     *          {5L, 7L}
+     *      },
+     *      {
+     *          {1L, 3L},
+     *          {0L, 2L}
+     *      }
+     *  }
+     * }
+ * The result indicates that the first substring match is gs("123") in key1 + * at index 4 to 6 which matches the substring in key2 + * at index 5 to 7. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2. + */ + CompletableFuture> lcsIdx(GlideString key1, GlideString key2); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -769,6 +854,51 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdx(String key1, String key2, long minMatchLen); + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @param minMatchLen The minimum length of matches to include in the result. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd123") and key2 + * holds the GlideString gs("bcdef123") then the sample result would be + *
{@code
+     * new Long[][][] {
+     *      {
+     *          {4L, 6L},
+     *          {5L, 7L}
+     *      },
+     *      {
+     *          {1L, 3L},
+     *          {0L, 2L}
+     *      }
+     *  }
+     * }
+ * The result indicates that the first substring match is gs("123") in key1 + * at index 4 to 6 which matches the substring in key2 + * at index 5 to 7. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2. + */ + CompletableFuture> lcsIdx( + GlideString key1, GlideString key2, long minMatchLen); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -814,6 +944,52 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdxWithMatchLen(String key1, String key2); + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd1234") and key2 + * holds the GlideString gs("bcdef1234") then the sample result would be + *
{@code
+     * new Object[] {
+     *      new Object[] {
+     *          new Long[] {4L, 7L},
+     *          new Long[] {5L, 8L},
+     *          4L},
+     *      new Object[] {
+     *          new Long[] {1L, 3L},
+     *          new Long[] {0L, 2L},
+     *          3L}
+     *      }
+     * }
+ * The result indicates that the first substring match is gs("1234") in + * key1 + * at index 4 to 7 which matches the substring in key2 + * at index 5 to 8 and the last element in the array is the + * length of the substring match which is 4. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2 and + * the last element in the array is the length of the substring match which is 3. + */ + CompletableFuture> lcsIdxWithMatchLen(GlideString key1, GlideString key2); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -860,4 +1036,52 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdxWithMatchLen( String key1, String key2, long minMatchLen); + + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @param minMatchLen The minimum length of matches to include in the result. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd1234") and key2 + * holds the GlideString gs("bcdef1234") then the sample result would be + *
{@code
+     * new Object[] {
+     *      new Object[] {
+     *          new Long[] {4L, 7L},
+     *          new Long[] {5L, 8L},
+     *          4L},
+     *      new Object[] {
+     *          new Long[] {1L, 3L},
+     *          new Long[] {0L, 2L},
+     *          3L}
+     *      }
+     * }
+ * The result indicates that the first substring match is gs("1234") in + * key1 + * at index 4 to 7 which matches the substring in key2 + * at index 5 to 8 and the last element in the array is the + * length of the substring match which is 4. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2 and + * the last element in the array is the length of the substring match which is 3. + */ + CompletableFuture> lcsIdxWithMatchLen( + GlideString key1, GlideString key2, long minMatchLen); } diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index f9dbb589c6..e16e8675cf 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -11270,6 +11270,31 @@ public void lcs() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcs_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = new GlideString[] {key1, key2}; + GlideString value = gs("foo"); + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lcs(key1, key2); + GlideString payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcs_with_len_option() { @@ -11295,6 +11320,31 @@ public void lcs_with_len_option() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcs_with_len_option_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = new GlideString[] {key1, key2, gs(LEN_REDIS_API)}; + Long value = 3L; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lcsLen(key1, key2); + Long payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdx() { @@ -11320,6 +11370,31 @@ public void lcsIdx() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdx_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = new GlideString[] {key1, key2, gs(IDX_COMMAND_STRING)}; + Map value = Map.of("matches", new Long[][][] {{{1L, 3L}, {0L, 2L}}}, "len", 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdx(key1, key2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdx_throws_NullPointerException() { @@ -11366,6 +11441,39 @@ public void lcsIdx_with_options() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdx_with_options_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = + new GlideString[] { + key1, key2, gs(IDX_COMMAND_STRING), gs(MINMATCHLEN_COMMAND_STRING), gs("2") + }; + Map value = + Map.of( + "matches", + new Object[] {new Object[] {new Long[] {1L, 3L}, new Long[] {0L, 2L}, 3L}}, + "len", + 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdx(key1, key2, 2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdxWithMatchLen() { @@ -11396,6 +11504,37 @@ public void lcsIdxWithMatchLen() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdxWithMatchLen_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = + new GlideString[] {key1, key2, gs(IDX_COMMAND_STRING), gs(WITHMATCHLEN_COMMAND_STRING)}; + Map value = + Map.of( + "matches", + new Object[] {new Object[] {new Long[] {1L, 3L}, new Long[] {0L, 2L}, 3L}}, + "len", + 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdxWithMatchLen(key1, key2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdxWithMatchLen_with_options() { @@ -11434,6 +11573,44 @@ public void lcsIdxWithMatchLen_with_options() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdxWithMatchLen_with_options_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = + new GlideString[] { + key1, + key2, + gs(IDX_COMMAND_STRING), + gs(MINMATCHLEN_COMMAND_STRING), + gs("2"), + gs(WITHMATCHLEN_COMMAND_STRING) + }; + Map value = + Map.of( + "matches", + new Object[] {new Object[] {new Long[] {1L, 3L}, new Long[] {0L, 2L}, 3L}}, + "len", + 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdxWithMatchLen(key1, key2, 2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void watch_returns_success() { diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index 30c731bb5d..d5372ffca3 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -9773,6 +9773,36 @@ public void lcs(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lcs_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7.0.0"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString key3 = gs("{key}-3" + UUID.randomUUID()); + GlideString notExistingKey = gs("{key}-4" + UUID.randomUUID()); + + // keys does not exist or is empty + assertEquals(gs(""), client.lcs(key1, key2).get()); + + // setting string values + client.set(key1, gs("abcd")); + client.set(key2, gs("bcde")); + client.set(key3, gs("wxyz")); + + // getting the lcs + assertEquals(gs(""), client.lcs(key1, key3).get()); + assertEquals(gs("bcd"), client.lcs(key1, key2).get()); + + // non set keys are used + client.sadd(notExistingKey, new GlideString[] {gs("setmember")}).get(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.lcs(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -9803,6 +9833,36 @@ public void lcs_with_len_option(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lcs_with_len_option_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7.0.0"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString key3 = gs("{key}-3" + UUID.randomUUID()); + GlideString notExistingKey = gs("{key}-4" + UUID.randomUUID()); + + // keys does not exist or is empty + assertEquals(0, client.lcsLen(key1, key2).get()); + + // setting string values + client.set(key1, gs("abcd")); + client.set(key2, gs("bcde")); + client.set(key3, gs("wxyz")); + + // getting the lcs + assertEquals(0, client.lcsLen(key1, key3).get()); + assertEquals(3, client.lcsLen(key1, key2).get()); + + // non set keys are used + client.sadd(notExistingKey, new GlideString[] {gs("setmember")}).get(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.lcs(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -10149,6 +10209,89 @@ public void lcsIdx(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lcsIdx_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7.0.0"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString notExistingKey = gs("{key}-4" + UUID.randomUUID()); + + // keys does not exist or is empty + Map result = client.lcsIdx(key1, key2).get(); + assertDeepEquals(new Object[0], result.get("matches")); + assertEquals(0L, result.get("len")); + result = client.lcsIdx(key1, key2, 10L).get(); + assertDeepEquals(new Object[0], result.get("matches")); + assertEquals(0L, result.get("len")); + result = client.lcsIdxWithMatchLen(key1, key2).get(); + assertDeepEquals(new Object[0], result.get("matches")); + assertEquals(0L, result.get("len")); + + // setting string values + client.set(key1, gs("abcdefghijk")); + client.set(key2, gs("defjkjuighijk")); + + // LCS with only IDX + Object expectedMatchesObject = new Long[][][] {{{6L, 10L}, {8L, 12L}}, {{3L, 5L}, {0L, 2L}}}; + result = client.lcsIdx(key1, key2).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX and WITHMATCHLEN + expectedMatchesObject = + new Object[] { + new Object[] {new Long[] {6L, 10L}, new Long[] {8L, 12L}, 5L}, + new Object[] {new Long[] {3L, 5L}, new Long[] {0L, 2L}, 3L} + }; + result = client.lcsIdxWithMatchLen(key1, key2).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX and MINMATCHLEN + expectedMatchesObject = new Long[][][] {{{6L, 10L}, {8L, 12L}}}; + result = client.lcsIdx(key1, key2, 4).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX and a negative MINMATCHLEN + expectedMatchesObject = new Long[][][] {{{6L, 10L}, {8L, 12L}}, {{3L, 5L}, {0L, 2L}}}; + result = client.lcsIdx(key1, key2, -1L).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX, MINMATCHLEN, and WITHMATCHLEN + expectedMatchesObject = + new Object[] {new Object[] {new Long[] {6L, 10L}, new Long[] {8L, 12L}, 5L}}; + result = client.lcsIdxWithMatchLen(key1, key2, 4L).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // non-string keys are used + client.sadd(notExistingKey, new GlideString[] {gs("setmember")}).get(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.lcsIdx(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + + executionException = + assertThrows( + ExecutionException.class, () -> client.lcsIdx(notExistingKey, key1, 10L).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + + executionException = + assertThrows( + ExecutionException.class, () -> client.lcsIdxWithMatchLen(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + + executionException = + assertThrows( + ExecutionException.class, + () -> client.lcsIdxWithMatchLen(notExistingKey, key1, 10L).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients")