Skip to content

Commit ce7ff9b

Browse files
updates unit tests and adds github action ci support (#113)
* updates unit tests adds github action ci support * adds more unit tests * fixes windows related unit tests
1 parent 04c0405 commit ce7ff9b

15 files changed

Lines changed: 974 additions & 110 deletions

‎.github/workflows/ci.yml‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master]
8+
9+
permissions:
10+
contents: read
11+
checks: write
12+
pull-requests: write
13+
14+
concurrency:
15+
group: ci-${{ github.head_ref || github.run_id }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
test:
20+
strategy:
21+
matrix:
22+
os: [ubuntu-latest, macos-latest, windows-latest]
23+
fail-fast: false
24+
runs-on: ${{ matrix.os }}
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- uses: actions/setup-java@v4
29+
with:
30+
java-version: '17'
31+
distribution: 'temurin'
32+
cache: 'maven'
33+
34+
- name: Build and test
35+
run: ./mvnw --batch-mode -no-transfer-progress prepare-package -Pci
36+
shell: bash
37+
38+
- uses: mikepenz/action-junit-report@v4
39+
if: always()
40+
with:
41+
report_paths: '**/target/surefire-reports/TEST-*.xml'
42+
check_name: Test Report (${{ matrix.os }})
43+
44+
- uses: actions/upload-artifact@v4
45+
if: always()
46+
with:
47+
name: coverage-${{ matrix.os }}
48+
path: '**/target/site/jacoco/'
49+
if-no-files-found: ignore
50+
51+
- uses: madrapps/jacoco-report@v1.6.1
52+
if: github.event_name == 'pull_request' && runner.os == 'Linux'
53+
with:
54+
paths: |
55+
${{ github.workspace }}/ls/server/target/site/jacoco/jacoco.xml
56+
${{ github.workspace }}/core/target/site/jacoco/jacoco.xml
57+
token: ${{ secrets.GITHUB_TOKEN }}
58+
title: Coverage Report
59+
update-comment: true

‎ls/server/src/test/java/org/opencds/cqf/cql/ls/server/LanguageServerTest.java‎

Lines changed: 0 additions & 86 deletions
This file was deleted.

‎ls/server/src/test/java/org/opencds/cqf/cql/ls/server/config/TestConfig.java‎

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package org.opencds.cqf.cql.ls.server.manager;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertNotNull;
5+
import static org.junit.jupiter.api.Assertions.assertSame;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
8+
import java.net.URI;
9+
import java.util.Collections;
10+
import java.util.List;
11+
import org.cqframework.cql.cql2elm.CqlCompilerOptions;
12+
import org.cqframework.cql.cql2elm.LibraryBuilder.SignatureLevel;
13+
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
14+
import org.eclipse.lsp4j.FileChangeType;
15+
import org.eclipse.lsp4j.FileEvent;
16+
import org.junit.jupiter.api.BeforeEach;
17+
import org.junit.jupiter.api.Test;
18+
import org.opencds.cqf.cql.ls.core.ContentService;
19+
import org.opencds.cqf.cql.ls.core.utility.Uris;
20+
import org.opencds.cqf.cql.ls.server.event.DidChangeWatchedFilesEvent;
21+
import org.opencds.cqf.cql.ls.server.service.TestContentService;
22+
23+
class CompilerOptionsManagerTest {
24+
25+
private CompilerOptionsManager manager;
26+
27+
// A URI whose "head" (parent path) is /org/opencds/cqf/cql/ls/server/
28+
// TestContentService.read will be called for the cql-options.json path, returning null
29+
// (no such classpath resource), so default options are used.
30+
private static final URI TEST_URI = Uris.parseOrNull("/org/opencds/cqf/cql/ls/server/One.cql");
31+
32+
@BeforeEach
33+
void setUp() {
34+
ContentService cs = new TestContentService();
35+
manager = new CompilerOptionsManager(cs);
36+
}
37+
38+
// -----------------------------------------------------------------------
39+
// getOptions — returns options enriched with required flags
40+
// -----------------------------------------------------------------------
41+
42+
@Test
43+
void getOptions_noOptionsFile_returnsNonNull() {
44+
CqlCompilerOptions options = manager.getOptions(TEST_URI);
45+
assertNotNull(options);
46+
}
47+
48+
@Test
49+
void getOptions_alwaysIncludesEnableLocators() {
50+
CqlCompilerOptions options = manager.getOptions(TEST_URI);
51+
assertTrue(options.getOptions().contains(CqlCompilerOptions.Options.EnableLocators));
52+
}
53+
54+
@Test
55+
void getOptions_alwaysIncludesEnableResultTypes() {
56+
CqlCompilerOptions options = manager.getOptions(TEST_URI);
57+
assertTrue(options.getOptions().contains(CqlCompilerOptions.Options.EnableResultTypes));
58+
}
59+
60+
@Test
61+
void getOptions_alwaysIncludesEnableAnnotations() {
62+
CqlCompilerOptions options = manager.getOptions(TEST_URI);
63+
assertTrue(options.getOptions().contains(CqlCompilerOptions.Options.EnableAnnotations));
64+
}
65+
66+
@Test
67+
void getOptions_signatureLevelIsAll() {
68+
CqlCompilerOptions options = manager.getOptions(TEST_URI);
69+
assertEquals(SignatureLevel.All, options.getSignatureLevel());
70+
}
71+
72+
// -----------------------------------------------------------------------
73+
// caching — same instance returned on second call
74+
// -----------------------------------------------------------------------
75+
76+
@Test
77+
void getOptions_secondCall_returnsCachedInstance() {
78+
CqlCompilerOptions first = manager.getOptions(TEST_URI);
79+
CqlCompilerOptions second = manager.getOptions(TEST_URI);
80+
assertSame(first, second);
81+
}
82+
83+
// -----------------------------------------------------------------------
84+
// clearOptions — evicts cache so next call re-reads
85+
// -----------------------------------------------------------------------
86+
87+
@Test
88+
void clearOptions_evictsCache() {
89+
manager.getOptions(TEST_URI); // populate cache
90+
manager.clearOptions(TEST_URI);
91+
CqlCompilerOptions second = manager.getOptions(TEST_URI);
92+
// After clearing, a new instance is created and still satisfies the required-flags contract.
93+
assertTrue(second.getOptions().contains(CqlCompilerOptions.Options.EnableLocators));
94+
}
95+
96+
// -----------------------------------------------------------------------
97+
// onMessageEvent — cql-options.json change clears cache
98+
// -----------------------------------------------------------------------
99+
100+
@Test
101+
void onMessageEvent_cqlOptionsChanged_clearsCache() {
102+
manager.getOptions(TEST_URI); // populate cache
103+
104+
// Simulate a file-watch event for a cql-options.json under the same root.
105+
String optionsUri = Uris.getHead(TEST_URI).toString() + "/cql/cql-options.json";
106+
FileEvent fileEvent = new FileEvent(optionsUri, FileChangeType.Changed);
107+
DidChangeWatchedFilesParams params = new DidChangeWatchedFilesParams(List.of(fileEvent));
108+
manager.onMessageEvent(new DidChangeWatchedFilesEvent(params));
109+
110+
CqlCompilerOptions second = manager.getOptions(TEST_URI);
111+
// After clearing via event, the options must still be enriched.
112+
assertNotNull(second);
113+
assertTrue(second.getOptions().contains(CqlCompilerOptions.Options.EnableLocators));
114+
}
115+
116+
@Test
117+
void onMessageEvent_unrelatedFile_doesNotClearCache() {
118+
CqlCompilerOptions first = manager.getOptions(TEST_URI); // populate cache
119+
120+
FileEvent fileEvent = new FileEvent("file:///workspace/SomeOtherFile.json", FileChangeType.Changed);
121+
DidChangeWatchedFilesParams params = new DidChangeWatchedFilesParams(Collections.singletonList(fileEvent));
122+
manager.onMessageEvent(new DidChangeWatchedFilesEvent(params));
123+
124+
CqlCompilerOptions second = manager.getOptions(TEST_URI);
125+
assertSame(first, second); // cache intact → same instance
126+
}
127+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.opencds.cqf.cql.ls.server.provider;
2+
3+
import static org.junit.jupiter.api.Assertions.assertNotNull;
4+
import static org.junit.jupiter.api.Assertions.assertNull;
5+
6+
import java.net.URI;
7+
import kotlinx.io.Source;
8+
import org.cqframework.cql.cql2elm.LibrarySourceProvider;
9+
import org.hl7.elm.r1.VersionedIdentifier;
10+
import org.junit.jupiter.api.BeforeAll;
11+
import org.junit.jupiter.api.Test;
12+
import org.opencds.cqf.cql.ls.core.ContentService;
13+
import org.opencds.cqf.cql.ls.server.service.TestContentService;
14+
15+
class ContentServiceSourceProviderTest {
16+
17+
private static ContentServiceSourceProvider provider;
18+
19+
@BeforeAll
20+
static void beforeAll() {
21+
ContentService cs = new TestContentService();
22+
// Root is arbitrary for TestContentService; it resolves by library name from classpath.
23+
URI root = URI.create("file:///workspace/");
24+
provider = new ContentServiceSourceProvider(root, cs);
25+
}
26+
27+
@Test
28+
void getLibrarySource_knownLibrary_returnsSource() {
29+
// "One" resolves to /org/opencds/cqf/cql/ls/server/One.cql on classpath.
30+
VersionedIdentifier id = new VersionedIdentifier().withId("One");
31+
32+
Source source = provider.getLibrarySource(id);
33+
34+
assertNotNull(source);
35+
}
36+
37+
@Test
38+
void getLibrarySource_unknownLibrary_returnsNull() {
39+
VersionedIdentifier id = new VersionedIdentifier().withId("DoesNotExistLibrary");
40+
41+
Source source = provider.getLibrarySource(id);
42+
43+
assertNull(source);
44+
}
45+
46+
@Test
47+
void getLibrarySource_implementsLibrarySourceProvider() {
48+
// Verify the class satisfies the LibrarySourceProvider contract expected by the compiler.
49+
assertNotNull((LibrarySourceProvider) provider);
50+
}
51+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.opencds.cqf.cql.ls.server.provider;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertNotNull;
6+
import static org.junit.jupiter.api.Assertions.assertThrows;
7+
8+
import java.util.List;
9+
import org.eclipse.lsp4j.Position;
10+
import org.eclipse.lsp4j.TextEdit;
11+
import org.junit.jupiter.api.BeforeAll;
12+
import org.junit.jupiter.api.Test;
13+
import org.opencds.cqf.cql.ls.core.ContentService;
14+
import org.opencds.cqf.cql.ls.server.service.TestContentService;
15+
16+
class FormattingProviderTest {
17+
18+
private static FormattingProvider formattingProvider;
19+
20+
@BeforeAll
21+
static void beforeAll() {
22+
ContentService cs = new TestContentService();
23+
formattingProvider = new FormattingProvider(cs);
24+
}
25+
26+
@Test
27+
void format_validCql_returnsOneEdit() throws Exception {
28+
List<TextEdit> edits = formattingProvider.format("/org/opencds/cqf/cql/ls/server/Two.cql");
29+
assertEquals(1, edits.size());
30+
TextEdit edit = edits.get(0);
31+
assertEquals(new Position(0, 0), edit.getRange().getStart());
32+
assertNotNull(edit.getNewText());
33+
assertFalse(edit.getNewText().isBlank());
34+
}
35+
36+
@Test
37+
void format_syntaxError_throwsIllegalArgument() {
38+
assertThrows(
39+
IllegalArgumentException.class,
40+
() -> formattingProvider.format("/org/opencds/cqf/cql/ls/server/SyntaxError.cql"));
41+
}
42+
}

0 commit comments

Comments
 (0)