Skip to content

Allows to run tests by suite or by name #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions protocol/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,8 @@ type

RunTestParams* = object
entryPoints*: seq[string]
suiteName*: string #Optional, if provided, only run tests in the suite. Takes precedence over testName
testNames*: seq[string] #Optional, if provided, only run the specific tests

RunTestProjectResult* = object
suites*: seq[RunTestSuiteResult]
3 changes: 2 additions & 1 deletion routes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,8 @@ proc runTests*(
if nimPath.isNone:
error "Nim path not found when running tests"
return RunTestProjectResult()
await runTests(params.entryPoints, nimPath.get())
let suiteName = if params.suiteName == "": none(string) else: some(params.suiteName)
await runTests(params.entryPoints, nimPath.get(), suiteName, params.testNames)

#Notifications
proc initialized*(ls: LanguageServer, _: JsonNode): Future[void] {.async.} =
Expand Down
21 changes: 17 additions & 4 deletions testrunner.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[os, strscans, tables, enumerate, strutils, xmlparser, xmltree]
import std/[os, strscans, tables, enumerate, strutils, xmlparser, xmltree, options, strformat]
import chronos, chronos/asyncproc
import protocol/types
import ls
Expand Down Expand Up @@ -77,19 +77,31 @@ proc parseTestSuite*(node: XmlNode): RunTestSuiteResult =
proc parseTestResults*(xmlContent: string): RunTestProjectResult =
let xml = parseXml(xmlContent)
for suiteNode in xml.findAll("testsuite"):
result.suites.add(parseTestSuite(suiteNode))
let suite = parseTestSuite(suiteNode)
# echo suite.name, " ", suite.testResults.len
if suite.testResults.len > 0:
result.suites.add(suite)

proc runTests*(entryPoints: seq[string], nimPath: string): Future[RunTestProjectResult] {.async.} =
proc runTests*(entryPoints: seq[string], nimPath: string, suiteName: Option[string], testNames: seq[string]): Future[RunTestProjectResult] {.async.} =
#For now only one entry point is supported
assert entryPoints.len == 1
let entryPoint = entryPoints[0]
let resultFile = (getTempDir() / "result.xml").absolutePath
if not fileExists(entryPoint):
error "Entry point does not exist", entryPoint = entryPoint
return RunTestProjectResult()


var args = @["c", "-r", entryPoints[0], fmt"--xml:{resultFile}"]
if suiteName.isSome:
args.add(fmt"{suiteName.get()}::")
else:
for testName in testNames:
args.add(testName)

let process = await startProcess(
nimPath,
arguments = @["c", "-r", entryPoints[0], "--xml:" & resultFile],
arguments = args,
options = {UsePath},
stderrHandle = AsyncProcess.Pipe,
stdoutHandle = AsyncProcess.Pipe,
Expand All @@ -102,6 +114,7 @@ proc runTests*(entryPoints: seq[string], nimPath: string): Future[RunTestProject
else:
assert fileExists(resultFile)
let xmlContent = readFile(resultFile)
# echo "XML CONTENT: ", xmlContent
result = parseTestResults(xmlContent)
except Exception as e:
let processOutput = string.fromBytes(process.stdoutStream.read().await)
Expand Down
2 changes: 1 addition & 1 deletion tests/projects/testrunner/tests/sampletests.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import unittest2

suite "Sample Tests":
test "Sample Test":
test "Sample Test alone":
check(1 == 1)

test "Global test":
Expand Down
59 changes: 57 additions & 2 deletions tests/textensions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ suite "Nimlangserver extensions":
let testProjectInfo = tests.projectInfo
check testProjectInfo.suites.len == 3
check testProjectInfo.suites["Sample Tests"].tests.len == 1
check testProjectInfo.suites["Sample Tests"].tests[0].name == "Sample Test"
check testProjectInfo.suites["Sample Tests"].tests[0].name == "Sample Test alone"
check testProjectInfo.suites["Sample Tests"].tests[0].file == "sampletests.nim"
check testProjectInfo.suites["Sample Tests"].tests[0].line == 4

Expand All @@ -119,4 +119,59 @@ suite "Nimlangserver extensions":
check runTestsRes.suites[0].failures == 0
check runTestsRes.suites[0].errors == 0
check runTestsRes.suites[0].skipped == 0
check runTestsRes.suites[0].time > 0.0 and runTestsRes.suites[0].time < 1.0
check runTestsRes.suites[0].time > 0.0 and runTestsRes.suites[0].time < 1.0

test "calling extension/runTest with a suite name should run the tests in the suite":
let initParams =
InitializeParams %* {
"processId": %getCurrentProcessId(),
"rootUri": fixtureUri("projects/testrunner/"),
"capabilities":
{"window": {"workDoneProgress": true}, "workspace": {"configuration": true}},
}
let initializeResult = waitFor client.initialize(initParams)

let suiteName = "Sample Suite"
let runTestsParams = RunTestParams(entryPoints: @["tests/projects/testrunner/tests/sampletests.nim".absolutePath], suiteName: suiteName)
let runTestsRes = client.call("extension/runTests", jsonutils.toJson(runTestsParams)).waitFor().jsonTo(
RunTestProjectResult
)
check runTestsRes.suites.len == 1
check runTestsRes.suites[0].name == suiteName
check runTestsRes.suites[0].tests == 3

test "calling extension/runTest with a test name should run the tests in the suite":
let initParams =
InitializeParams %* {
"processId": %getCurrentProcessId(),
"rootUri": fixtureUri("projects/testrunner/"),
"capabilities":
{"window": {"workDoneProgress": true}, "workspace": {"configuration": true}},
}

let initializeResult = waitFor client.initialize(initParams)

let testName = "Sample Test"
let runTestsParams = RunTestParams(entryPoints: @["tests/projects/testrunner/tests/sampletests.nim".absolutePath], testNames: @[testName])
let runTestsRes = client.call("extension/runTests", jsonutils.toJson(runTestsParams)).waitFor().jsonTo(RunTestProjectResult)

check runTestsRes.suites.len == 1
check runTestsRes.suites[0].tests == 1
check runTestsRes.suites[0].testResults[0].name == testName

test "calling extension/runTest with multiple test names should run the tests in the suite":
let initParams =
InitializeParams %* {
"processId": %getCurrentProcessId(),
"rootUri": fixtureUri("projects/testrunner/"),
"capabilities":
{"window": {"workDoneProgress": true}, "workspace": {"configuration": true}},
}
let initializeResult = waitFor client.initialize(initParams)

let testNames = @["Sample Test", "Sample Test 2"]
let runTestsParams = RunTestParams(entryPoints: @["tests/projects/testrunner/tests/sampletests.nim".absolutePath], testNames: testNames)
let runTestsRes = client.call("extension/runTests", jsonutils.toJson(runTestsParams)).waitFor().jsonTo(RunTestProjectResult)

check runTestsRes.suites.len == 1
check runTestsRes.suites[0].tests == 2
6 changes: 3 additions & 3 deletions tests/ttestrunner.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import unittest
import std/[os, osproc, strscans, tables, sequtils, enumerate, strutils]
import std/[os, osproc, strscans, tables, sequtils, enumerate, strutils, options]
import testhelpers
import testrunner
import chronos
Expand Down Expand Up @@ -27,7 +27,7 @@ suite "Test Parser":
let testProjectInfo = extractTestInfo(listTestsOutput)
check testProjectInfo.suites.len == 3
check testProjectInfo.suites["Sample Tests"].tests.len == 1
check testProjectInfo.suites["Sample Tests"].tests[0].name == "Sample Test"
check testProjectInfo.suites["Sample Tests"].tests[0].name == "Sample Test alone"
check testProjectInfo.suites["Sample Tests"].tests[0].file == "sampletests.nim"
check testProjectInfo.suites["Sample Tests"].tests[0].line == 4
check testProjectInfo.suites["Sample Suite"].tests.len == 3
Expand All @@ -36,7 +36,7 @@ suite "Test Parser":
suite "Test Runner":
test "should be able to run tests and retrieve results":
let entryPoint = getCurrentDir() / "tests" / "projects" / "testrunner" / "tests" / "sampletests.nim"
let testProjectResult = waitFor runTests(@[entryPoint], "nim")
let testProjectResult = waitFor runTests(@[entryPoint], "nim", none(string), @[])
check testProjectResult.suites.len == 4
check testProjectResult.suites[0].name == "Sample Tests"
check testProjectResult.suites[0].tests == 1
Expand Down