Skip to content

Test parser based on the output of unittest2 #316

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 6 commits into from
Apr 9, 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
3 changes: 2 additions & 1 deletion tests/all.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import
tnimlangserver,
tprojectsetup,
textensions,
tmisc
tmisc,
ttestrunner
4 changes: 4 additions & 0 deletions tests/projects/testrunner/config.nims
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# begin Nimble config (version 2)
when withDir(thisDir(), system.fileExists("nimble.paths")):
include "nimble.paths"
# end Nimble config
7 changes: 7 additions & 0 deletions tests/projects/testrunner/src/testrunner.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This is just an example to get you started. A typical library package
# exports the main API in this file. Note that you cannot rename this file
# but you can remove it if you wish.

proc add*(x, y: int): int =
## Adds two numbers together.
return x + y
12 changes: 12 additions & 0 deletions tests/projects/testrunner/src/testrunner/submodule.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This is just an example to get you started. Users of your library will
# import this file by writing ``import testrunner/submodule``. Feel free to rename or
# remove this file altogether. You may create additional modules alongside
# this file as required.

type
Submodule* = object
name*: string

proc initSubmodule*(): Submodule =
## Initialises a new ``Submodule`` object.
Submodule(name: "Anonymous")
12 changes: 12 additions & 0 deletions tests/projects/testrunner/testrunner.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Package

version = "0.1.0"
author = "jmgomez"
description = "A new awesome nimble package"
license = "MIT"
srcDir = "src"


# Dependencies

requires "nim", "https://github.com/jmgomez/nim-unittest2#list_tests"
24 changes: 24 additions & 0 deletions tests/projects/testrunner/tests/sampletests.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import unittest2

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

test "Global test":
check(1 == 1)

test "Global test 2":
check(1 == 1)

suite "Sample Suite":
test "Sample Test":
check(1 == 1)

test "Sample Test 2":
check(1 == 1)

test "Sample Test 3":
check(1 == 1)

test "Another global test":
check(1 == 1)
11 changes: 11 additions & 0 deletions tests/projects/testrunner/tests/test1.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is just an example to get you started. You may wish to put all of your
# tests into a single file, or separate them into multiple `test1`, `test2`
# etc. files (better names are recommended, just make sure the name starts with
# the letter 't').
#
# To run these tests, simply execute `nimble test`.

import unittest2

test "can add":
check true
57 changes: 57 additions & 0 deletions tests/testhelpers.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import std/[os, osproc, sequtils, strutils, sugar, unittest]

template cd*(dir: string, body: untyped) =
## Sets the current dir to ``dir``, executes ``body`` and restores the
## previous working dir.
let lastDir = getCurrentDir()
setCurrentDir(dir)
block:
defer:
setCurrentDir(lastDir)
body

template createNewDir*(dir: string) =
removeDir dir
createDir dir

template cdNewDir*(dir: string, body: untyped) =
createNewDir dir
cd dir:
body

let
rootDir = getCurrentDir()
nimblePath* = findExe "nimble"
installDir* = rootDir / "tests" / "nimbleDir"

type ProcessOutput* = tuple[output: string, exitCode: int]

proc execNimble*(args: varargs[string]): ProcessOutput =
var quotedArgs = @args
if not args.anyIt("--nimbleDir:" in it or "-l" == it or "--local" == it):
quotedArgs.insert("--nimbleDir:" & installDir)
quotedArgs.insert(nimblePath)
quotedArgs = quotedArgs.map((x: string) => x.quoteShell)

let path {.used.} = getCurrentDir().parentDir() / "src"

var cmd =
when not defined(windows):
"PATH=" & path & ":$PATH " & quotedArgs.join(" ")
else:
quotedArgs.join(" ")
when defined(macosx):
# TODO: Yeah, this is really specific to my machine but for my own sanity...
cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib " & cmd

result = execCmdEx(cmd)
checkpoint(cmd)
checkpoint(result.output)

proc execNimbleYes*(args: varargs[string]): ProcessOutput =
execNimble(@args & "-y")

proc createNimbleProject*(projectDir: string) =
cdNewDir projectDir:
let (output, exitCode) = execNimbleYes("init")
check exitCode == 0
60 changes: 2 additions & 58 deletions tests/tprojectsetup.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,12 @@ import ../protocol/[enums, types]
import
std/
[
options, unittest, json, os, jsonutils, sequtils, strutils, sugar, strformat,
osproc,
options, unittest, json, os, jsonutils, sequtils, strutils, sugar, strformat
]
import json_rpc/[rpcclient]
import chronicles
import lspsocketclient

template cd*(dir: string, body: untyped) =
## Sets the current dir to ``dir``, executes ``body`` and restores the
## previous working dir.
let lastDir = getCurrentDir()
setCurrentDir(dir)
block:
defer:
setCurrentDir(lastDir)
body

template createNewDir*(dir: string) =
removeDir dir
createDir dir

template cdNewDir*(dir: string, body: untyped) =
createNewDir dir
cd dir:
body

let
rootDir = getCurrentDir()
nimblePath* = findExe "nimble"
installDir* = rootDir / "tests" / "nimbleDir"

type ProcessOutput* = tuple[output: string, exitCode: int]

proc execNimble*(args: varargs[string]): ProcessOutput =
var quotedArgs = @args
if not args.anyIt("--nimbleDir:" in it or "-l" == it or "--local" == it):
quotedArgs.insert("--nimbleDir:" & installDir)
quotedArgs.insert(nimblePath)
quotedArgs = quotedArgs.map((x: string) => x.quoteShell)

let path {.used.} = getCurrentDir().parentDir() / "src"

var cmd =
when not defined(windows):
"PATH=" & path & ":$PATH " & quotedArgs.join(" ")
else:
quotedArgs.join(" ")
when defined(macosx):
# TODO: Yeah, this is really specific to my machine but for my own sanity...
cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib " & cmd

result = execCmdEx(cmd)
checkpoint(cmd)
checkpoint(result.output)

proc execNimbleYes*(args: varargs[string]): ProcessOutput =
execNimble(@args & "-y")

proc createNimbleProject(projectDir: string) =
cdNewDir projectDir:
let (output, exitCode) = execNimbleYes("init")
check exitCode == 0
import testhelpers

suite "nimble setup":
let cmdParams = CommandLineParams(transport: some socket, port: getNextFreePort())
Expand Down
75 changes: 75 additions & 0 deletions tests/ttestrunner.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import unittest
import std/[os, osproc, strscans, tables, sequtils, enumerate, strutils]
import testhelpers

type
TestInfo* = object
name*: string
line*: int
file*: string

TestSuiteInfo* = object
name*: string #The suite name, empty if it's a global test
tests*: seq[TestInfo]

TestProjectInfo* = object
entryPoints*: seq[string]
suites*: Table[string, TestSuiteInfo]




proc extractTestInfo*(rawOutput: string): TestProjectInfo =
result.suites = initTable[string, TestSuiteInfo]()
let lines = rawOutput.split("\n")
var currentSuite = ""

for i, line in enumerate(lines):
var name, file, ignore: string
var lineNumber: int
if scanf(line, "Suite: $*", name):
currentSuite = name.strip()
result.suites[currentSuite] = TestSuiteInfo(name: currentSuite)
# echo "Found suite: ", currentSuite

elif scanf(line, "$*Test: $*", ignore, name):
let insideSuite = line.startsWith("\t")
# Use currentSuite if inside a suite, empty string if not
let suiteName = if insideSuite: currentSuite else: ""

#File is always next line of a test
if scanf(lines[i+1], "$*File:$*:$i", ignore, file, lineNumber):
var testInfo = TestInfo(name: name.strip(), file: file.strip(), line: lineNumber)
# echo "Adding test: ", testInfo.name, " to suite: ", suiteName
result.suites[suiteName].tests.add(testInfo)



suite "Test Parser":
test "should be able to list tests from an entry point":
#A project can have multiple entry points for the tests, they are specified in the test runner.
#We first need to install the project, as it uses a custom version of unittest2 (until it get merged).
let projectDir = getCurrentDir() / "tests" / "projects" / "testrunner"
cd projectDir:
let (output, _) = execNimble("install", "-l")
discard execNimble("setup")
let (listTestsOutput, _) = execCmdEx("nim c -d:unittest2ListTests -r ./tests/test1.nim")
let testProjectInfo = extractTestInfo(listTestsOutput)
check testProjectInfo.suites.len == 1
check testProjectInfo.suites["test1.nim"].tests.len == 1
check testProjectInfo.suites["test1.nim"].tests[0].name == "can add"
check testProjectInfo.suites["test1.nim"].tests[0].file == "test1.nim"
check testProjectInfo.suites["test1.nim"].tests[0].line == 10

test "should be able to list tests and suites":
let projectDir = getCurrentDir() / "tests" / "projects" / "testrunner"
cd projectDir:
let (listTestsOutput, _) = execCmdEx("nim c -d:unittest2ListTests -r ./tests/sampletests.nim")
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].file == "sampletests.nim"
check testProjectInfo.suites["Sample Tests"].tests[0].line == 4
check testProjectInfo.suites["Sample Suite"].tests.len == 3
check testProjectInfo.suites["sampletests.nim"].tests.len == 3