Skip to content

Commit 43c3156

Browse files
committed
test: add ScoreOfFilterMatchTest
1 parent f3729e7 commit 43c3156

3 files changed

Lines changed: 139 additions & 2 deletions

File tree

org.eclipse.lsp4e.test/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: Tests for language server bundle (Incubation)
44
Bundle-SymbolicName: org.eclipse.lsp4e.test;singleton:=true
5-
Bundle-Version: 0.15.22.qualifier
5+
Bundle-Version: 0.15.23.qualifier
66
Fragment-Host: org.eclipse.lsp4e
77
Bundle-Vendor: Eclipse LSP4E
88
Bundle-RequiredExecutionEnvironment: JavaSE-17

org.eclipse.lsp4e.test/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</parent>
99
<artifactId>org.eclipse.lsp4e.test</artifactId>
1010
<packaging>eclipse-test-plugin</packaging>
11-
<version>0.15.22-SNAPSHOT</version>
11+
<version>0.15.23-SNAPSHOT</version>
1212

1313
<properties>
1414
<os-jvm-flags /> <!-- for the default case -->
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Vegard IT GmbH and others.
3+
* This program and the accompanying materials are made
4+
* available under the terms of the Eclipse Public License 2.0
5+
* which is available at https://www.eclipse.org/legal/epl-2.0/
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Sebastian Thomschke (Vegard IT GmbH) - initial implementation
11+
*******************************************************************************/
12+
package org.eclipse.lsp4e.test.completion;
13+
14+
import static org.junit.Assert.*;
15+
16+
import java.util.Random;
17+
import java.util.concurrent.Executors;
18+
import java.util.concurrent.TimeUnit;
19+
import java.util.concurrent.TimeoutException;
20+
21+
import org.eclipse.lsp4e.operations.completion.CompletionProposalTools;
22+
import org.junit.Test;
23+
24+
/**
25+
* Test cases for {@link CompletionProposalTools#getScoreOfFilterMatch(String, String)}
26+
*/
27+
public class ScoreOfFilterMatchTest {
28+
private static final Random RANDOM = new Random();
29+
30+
private static String generateRandomString(final int maxLength) {
31+
final var length = RANDOM.nextInt(maxLength + 1);
32+
if (length == 0)
33+
return "";
34+
var chars = "abcdefghijklmnopqrstuvwxyzäöüß";
35+
chars = "_" + chars + chars.toUpperCase();
36+
final var sb = new StringBuilder(length);
37+
for (int i = 0; i < length; i++) {
38+
sb.append(chars.charAt(RANDOM.nextInt(chars.length())));
39+
}
40+
return sb.toString();
41+
}
42+
43+
@Test
44+
public void testCaseInsensitivity() {
45+
final var documentFilter = "Example";
46+
final var completionFilter = "eXaMpLe";
47+
final int expectedScore = 0;
48+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
49+
assertEquals("The score should be 0 for case-insensitive matches.", expectedScore, actualScore);
50+
}
51+
52+
@Test
53+
public void testEmptyCompletionFilter() {
54+
final var documentFilter = "example";
55+
final var completionFilter = "";
56+
final int expectedScore = -1;
57+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
58+
assertEquals("The score should be -1 for an empty completionFilter.", expectedScore, actualScore);
59+
}
60+
61+
@Test
62+
public void testEmptyDocumentFilter() {
63+
final var documentFilter = "";
64+
final var completionFilter = "example";
65+
final int expectedScore = 0;
66+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
67+
assertEquals("The score should be 0 for an empty documentFilter.", expectedScore, actualScore);
68+
}
69+
70+
/**
71+
* Test case for https://github.com/eclipse-lsp4e/lsp4e/issues/1132
72+
*/
73+
@Test
74+
public void testRandomFilters() {
75+
final int testCases = 50_000; // Number of random test cases to try
76+
final int timeoutMS = 3; // Timeout threshold for detecting infinite loops
77+
78+
final var executor = Executors.newSingleThreadExecutor();
79+
80+
for (int i = 0; i < testCases; i++) {
81+
final var commonPrefix = generateRandomString(2); // String with length of 0-2 chars
82+
final var documentFilter = commonPrefix + generateRandomString(5);
83+
final var completionFilter = commonPrefix + generateRandomString(15);
84+
85+
final var future = executor
86+
.submit(() -> CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter));
87+
88+
try {
89+
future.get(timeoutMS, TimeUnit.SECONDS);
90+
} catch (final TimeoutException e) {
91+
future.cancel(true); // Interrupt stuck execution
92+
fail("Possible infinite loop detected in getScoreOfFilterMatch with inputs: " + "documentFilter='"
93+
+ documentFilter + "', completionFilter='" + completionFilter + "'");
94+
} catch (Exception e) {
95+
fail("Unexpected exception: " + e.getMessage());
96+
}
97+
}
98+
99+
executor.shutdown();
100+
}
101+
102+
@Test
103+
public void testExactMatch() {
104+
final var documentFilter = "example";
105+
final var completionFilter = "example";
106+
final int expectedScore = 0;
107+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
108+
assertEquals("The score should be 0 for exact matches.", expectedScore, actualScore);
109+
}
110+
111+
@Test
112+
public void testNoMatch() {
113+
final var documentFilter = "foo";
114+
final var completionFilter = "example";
115+
final int expectedScore = -1;
116+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
117+
assertEquals("The score should be -1 when there's no match.", expectedScore, actualScore);
118+
}
119+
120+
@Test
121+
public void testPrefixMatch() {
122+
final var documentFilter = "ex";
123+
final var completionFilter = "example";
124+
final int expectedScore = 0;
125+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
126+
assertEquals("The score should be 0 when documentFilter is a prefix.", expectedScore, actualScore);
127+
}
128+
129+
@Test
130+
public void testScatteredMatch() {
131+
final var documentFilter = "eap";
132+
final var completionFilter = "example";
133+
final int expectedScore = 6;
134+
final int actualScore = CompletionProposalTools.getScoreOfFilterMatch(documentFilter, completionFilter);
135+
assertEquals("The score should account for scattered characters.", expectedScore, actualScore);
136+
}
137+
}

0 commit comments

Comments
 (0)