Skip to content

Commit 61f37f8

Browse files
afuchermarlon-jsilvamarlonjsilva
authored
add intellij integration test structure (#76)
* add intellij integration test structure * configure testdata and assert files * try to execute slurp action * set lsp server path * interacting with editor - wip * executa slurp e valida arquivo * fix dispatch-all-until * remove unnecessary lines * refactoring tests - wip * adding --debug to test.yaml * bump LSP4IJ version * bump LSP4IJ version * improve tests * refactor some functions * disable comment from test report * remove debug flag from test * apply code review * change test project name to be more explicit --------- Co-authored-by: Marlon Silva <[email protected]> Co-authored-by: Marlon Silva <[email protected]>
1 parent b3a1e5f commit 61f37f8

File tree

9 files changed

+229
-5
lines changed

9 files changed

+229
-5
lines changed

.github/workflows/test.yaml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Tests
2+
on:
3+
pull_request:
4+
5+
permissions:
6+
contents: read
7+
checks: write
8+
pull-requests: write
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0
17+
18+
- name: Setup Java
19+
uses: actions/setup-java@v4
20+
with:
21+
distribution: 'temurin'
22+
java-version: 17
23+
cache: 'gradle'
24+
25+
- name: Install Clojure
26+
uses: DeLaGuardo/setup-clojure@master
27+
with:
28+
bb: '1.12.196'
29+
cli: 1.12.0.1530
30+
31+
- name: Run tests
32+
run: ./gradlew test
33+
34+
- name: Publish Test Report
35+
uses: mikepenz/action-junit-report@v5
36+
if: success() || failure() # always run even if the previous step fails
37+
with:
38+
report_paths: '**/build/test-results/test/TEST-*.xml'
39+
simplified_summary: true
40+
comment: false

bb.edn

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{:paths ["src/scripts"]
22
:tasks {tag scripts/tag
33
build-plugin scripts/build-plugin
4+
test scripts/tests
45
install-plugin scripts/install-plugin
56
publish-plugin scripts/publish-plugin}}

build.gradle.kts

+37-3
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,24 @@ repositories {
3535

3636
dependencies {
3737
implementation ("org.clojure:clojure:1.12.0")
38-
implementation ("com.github.ericdallo:clj4intellij:0.7.1")
38+
implementation ("com.github.ericdallo:clj4intellij:0.8.0")
3939
implementation ("seesaw:seesaw:1.5.0")
4040
implementation ("camel-snake-kebab:camel-snake-kebab:0.4.3")
4141
implementation ("com.rpl:proxy-plus:0.0.9")
4242
implementation ("dev.weavejester:cljfmt:0.13.0")
4343
implementation ("com.github.clojure-lsp:clojure-lsp:2025.01.22-23.28.23")
44+
implementation ("nrepl:nrepl:1.3.1")
45+
46+
testImplementation("junit:junit:latest.release")
47+
testImplementation("org.junit.platform:junit-platform-launcher:latest.release")
48+
testRuntimeOnly ("dev.clojurephant:jovial:0.4.2")
4449
}
4550

4651
sourceSets {
4752
main {
4853
java.srcDirs("src/main", "src/gen")
4954
if (project.gradle.startParameter.taskNames.contains("buildPlugin") ||
55+
project.gradle.startParameter.taskNames.contains("clojureRepl") ||
5056
project.gradle.startParameter.taskNames.contains("runIde")) {
5157
resources.srcDirs("src/main/dev-resources")
5258
}
@@ -146,6 +152,10 @@ tasks {
146152
systemProperty("jb.consents.confirmation.enabled", "false")
147153
}
148154

155+
test {
156+
systemProperty("idea.mimic.jar.url.connection", "true")
157+
}
158+
149159
signPlugin {
150160
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
151161
privateKey.set(System.getenv("PRIVATE_KEY"))
@@ -165,6 +175,26 @@ tasks {
165175
enabled = false
166176
}
167177

178+
clojureRepl {
179+
dependsOn("compileClojure")
180+
classpath.from(sourceSets.main.get().runtimeClasspath
181+
+ file("build/classes/kotlin/main")
182+
+ file("build/clojure/main")
183+
)
184+
// doFirst {
185+
// println(classpath.asPath)
186+
// }
187+
forkOptions.jvmArgs = listOf("--add-opens=java.desktop/java.awt=ALL-UNNAMED",
188+
"--add-opens=java.desktop/java.awt.event=ALL-UNNAMED",
189+
"--add-opens=java.desktop/sun.awt=ALL-UNNAMED",
190+
"--add-opens=java.desktop/sun.font=ALL-UNNAMED",
191+
"--add-opens=java.base/java.lang=ALL-UNNAMED",
192+
"-Djava.system.class.loader=com.intellij.util.lang.PathClassLoader",
193+
"-Didea.mimic.jar.url.connection=true",
194+
"-Didea.force.use.core.classloader=true"
195+
)
196+
}
197+
168198
generateParser {
169199
source.set("src/main/gramar/clojure.bnf")
170200
targetRoot.set("src/gen")
@@ -180,14 +210,18 @@ tasks {
180210
}
181211
}
182212

213+
tasks.withType<Test>().configureEach {
214+
useJUnitPlatform()
215+
}
216+
183217
grammarKit {
184218
jflexRelease.set("1.7.0-1")
185219
grammarKitRelease.set("2021.1.2")
186220
intellijRelease.set("203.7717.81")
187221
}
188222

189223
clojure.builds.named("main") {
190-
classpath.from(sourceSets.main.get().runtimeClasspath.asPath)
224+
classpath.from(sourceSets.main.get().runtimeClasspath.asPath + "build/classes/kotlin/main")
191225
checkAll()
192226
aotAll()
193227
reflection.set("fail")
@@ -213,6 +247,6 @@ fun fetchLatestLsp4ijNightlyVersion(): String {
213247
println("Failed to fetch LSP4IJ nightly build version: ${e.message}")
214248
}
215249

216-
val minVersion = "0.0.1-20231213-012910"
250+
val minVersion = "0.12.1-20250404-161025"
217251
return if (minVersion < onlineVersion) onlineVersion else minVersion
218252
}

src/main/clojure/com/github/clojure_lsp/intellij/editor.clj

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
(ns com.github.clojure-lsp.intellij.editor
22
(:require
33
[com.github.clojure-lsp.intellij.db :as db]
4-
[com.github.clojure-lsp.intellij.editor :as editor])
4+
[com.github.clojure-lsp.intellij.editor :as editor]
5+
[com.github.ericdallo.clj4intellij.app-manager :as app-manager])
56
(:import
6-
[com.intellij.openapi.editor Editor]
7+
[com.intellij.openapi.editor CaretModel Editor LogicalPosition]
78
[com.intellij.openapi.fileEditor FileDocumentManager]
89
[com.intellij.openapi.project ProjectLocator]
910
[com.intellij.openapi.util.text StringUtil]
@@ -23,3 +24,11 @@
2324
(defn guess-project-for [^VirtualFile file]
2425
(or (.guessProjectForFile (ProjectLocator/getInstance) file)
2526
(first (db/all-projects))))
27+
28+
(defn move-caret-to-position
29+
"Moves the caret to the specified logical position in the editor."
30+
[^Editor editor line column]
31+
(let [caret ^CaretModel (.getCaretModel editor)
32+
new-position (LogicalPosition. line column)]
33+
@(app-manager/invoke-later!
34+
{:invoke-fn (fn [] (.moveToLogicalPosition caret new-position))})))

src/scripts/scripts.clj

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
(shell "git push origin HEAD")
3636
(shell "git push origin --tags"))
3737

38+
(defn tests []
39+
(shell "./gradlew test"))
40+
3841
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
3942
(defn build-plugin []
4043
(shell "./gradlew buildPlugin"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
(ns com.github.clojure-lsp.intellij.slurp-action-test
2+
(:require
3+
[clojure.test :refer [deftest is]]
4+
[com.github.clojure-lsp.intellij.editor :as editor]
5+
[com.github.clojure-lsp.intellij.test-utils :as test-utils]
6+
[com.github.ericdallo.clj4intellij.test :as clj4intellij.test])
7+
(:import
8+
[com.intellij.openapi.project Project]
9+
[com.intellij.testFramework.fixtures CodeInsightTestFixture]))
10+
11+
(set! *warn-on-reflection* true)
12+
13+
(deftest slurp-action-test
14+
"Tests the Forward Slurp editor action functionality in Clojure LSP.
15+
This test:
16+
1. Sets up a test project with a Clojure file
17+
2. Opens the file in the editor
18+
3. Sets up the LSP server
19+
4. Moves the caret to a specific position
20+
5. Executes the Forward Slurp action
21+
6. Verifies the resulting text matches the expected output
22+
23+
The test ensures that the Forward Slurp action correctly modifies the code structure
24+
by moving the closing parenthesis forward."
25+
(let [project-name "clojure.sample-project"
26+
{:keys [fixtures project deps-file]} (test-utils/setup-test-project project-name)
27+
clj-file (.copyFileToProject ^CodeInsightTestFixture fixtures "foo.clj")]
28+
(is (= project-name (.getName ^Project project)))
29+
(is deps-file)
30+
31+
(let [editor (test-utils/open-file-in-editor fixtures clj-file)]
32+
(test-utils/setup-lsp-server project)
33+
(editor/move-caret-to-position editor 2 8)
34+
(test-utils/run-editor-action "ClojureLSP.ForwardSlurp" project)
35+
(clj4intellij.test/dispatch-all)
36+
37+
(.checkResultByFile ^CodeInsightTestFixture fixtures "foo_expected.clj")
38+
39+
(test-utils/teardown-test-project project))))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
(ns com.github.clojure-lsp.intellij.test-utils
2+
(:require
3+
[com.github.clojure-lsp.intellij.client :as lsp-client]
4+
[com.github.clojure-lsp.intellij.server :as server]
5+
[com.github.ericdallo.clj4intellij.app-manager :as app-manager]
6+
[com.github.ericdallo.clj4intellij.test :as clj4intellij.test])
7+
(:import
8+
[com.github.clojure_lsp.intellij.extension SettingsState]
9+
[com.intellij.ide DataManager]
10+
[com.intellij.openapi.actionSystem ActionManager]
11+
[com.intellij.openapi.components ServiceManager]
12+
[com.intellij.testFramework.fixtures CodeInsightTestFixture]))
13+
14+
(set! *warn-on-reflection* true)
15+
16+
(defn get-editor-text
17+
"Returns the text content of the editor's document."
18+
[^CodeInsightTestFixture fixture]
19+
(-> fixture .getEditor .getDocument .getText))
20+
21+
(defn open-file-in-editor
22+
"Opens a file in the editor and returns the editor instance."
23+
[^CodeInsightTestFixture fixture file]
24+
(let [project (.getProject fixture)]
25+
(app-manager/write-command-action
26+
project
27+
(fn [] (.openFileInEditor fixture file)))
28+
(.getEditor fixture)))
29+
30+
(defn run-editor-action
31+
"Runs an editor action with the given ID for the specified project."
32+
[action-id project]
33+
(let [action (.getAction (ActionManager/getInstance) action-id)
34+
context (.getDataContext (DataManager/getInstance))]
35+
(app-manager/write-command-action
36+
project
37+
(fn []
38+
(.actionPerformed
39+
action
40+
(com.intellij.openapi.actionSystem.AnActionEvent/createFromDataContext action-id nil context))))))
41+
42+
(defn wait-lsp-start
43+
"Dispatches all events until the LSP server is started or the timeout is reached."
44+
[{:keys [project millis timeout]
45+
:or {millis 1000
46+
timeout 10000}}]
47+
(let [start-time (System/currentTimeMillis)]
48+
(loop []
49+
(let [current-time (System/currentTimeMillis)
50+
elapsed-time (- current-time start-time)
51+
status (lsp-client/server-status project)]
52+
(cond
53+
(>= elapsed-time timeout)
54+
(throw (ex-info "LSP server failed to start within timeout"
55+
{:elapsed-time elapsed-time
56+
:final-status status}))
57+
58+
(= status :started)
59+
true
60+
61+
:else
62+
(do
63+
(clj4intellij.test/dispatch-all)
64+
(Thread/sleep millis)
65+
(recur)))))))
66+
67+
(defn teardown-test-project
68+
"Shuts down all resources for the given project."
69+
[project]
70+
(server/shutdown! project))
71+
72+
(defn setup-test-project
73+
"Sets up a test project with the given name and optional deps.edn content.
74+
Returns a map with :fixture, :project, and :deps-file."
75+
([project-name]
76+
(setup-test-project project-name "{}"))
77+
([project-name deps-content]
78+
(let [fixtures (clj4intellij.test/setup project-name)
79+
deps-file (.createFile fixtures "deps.edn" deps-content)
80+
_ (.setTestDataPath fixtures "testdata")
81+
project (.getProject fixtures)]
82+
{:fixtures fixtures
83+
:project project
84+
:deps-file deps-file})))
85+
86+
(defn setup-lsp-server
87+
"Sets up and waits for the LSP server to be ready."
88+
[project]
89+
(let [my-settings ^SettingsState (ServiceManager/getService SettingsState)]
90+
(.loadState my-settings my-settings)
91+
(clj4intellij.test/dispatch-all)
92+
(wait-lsp-start {:project project})))

testdata/foo.clj

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(ns foo)
2+
3+
(println) "Oiii"

testdata/foo_expected.clj

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(ns foo)
2+
3+
(println "Oiii")

0 commit comments

Comments
 (0)