getnim/tests/tester.nim

299 lines
9.7 KiB
Nim

# Copyright (C) Dominik Picheta. All rights reserved.
# BSD-3-Clause License. Look at license.txt for more info.
import osproc, streams, unittest, strutils, os, sequtils, sugar, logging
var rootDir = getCurrentDir()
var exePath = rootDir / "bin" / addFileExt("getnim", ExeExt)
var nimbleDir = rootDir / "tests" / "nimbleDir"
var getnimDir = rootDir / "tests" / "getnimDir"
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)
body
setCurrentDir(lastDir)
template beginTest() =
# Clear custom dirs.
removeDir(nimbleDir)
createDir(nimbleDir)
removeDir(getnimDir)
createDir(getnimDir)
proc outputReader(stream: Stream, missedEscape: var bool): string =
result = ""
template handleEscape: untyped {.dirty.} =
missedEscape = false
result.add('\27')
let escape = stream.readStr(1)
result.add(escape)
if escape[0] == '[':
result.add(stream.readStr(2))
return
# TODO: This would be much easier to implement if `peek` was supported.
if missedEscape:
handleEscape()
while true:
let c = stream.readStr(1)
if c.len() == 0:
return
case c[0]
of '\c', '\l':
result.add(c[0])
return
of '\27':
if result.len > 0:
missedEscape = true
return
handleEscape()
else:
result.add(c[0])
proc exec(args: varargs[string], exe=exePath,
yes=true, liveOutput=false,
global=false): tuple[output: string, exitCode: int] =
var quotedArgs: seq[string] = @[exe]
if yes:
quotedArgs.add("-y")
quotedArgs.add(@args)
if not global:
quotedArgs.add("--nimbleDir:" & nimbleDir)
if exe.splitFile().name != "nimble":
quotedArgs.add("--getnimDir:" & getnimDir)
quotedArgs.add("--noColor")
for i in 0..quotedArgs.len-1:
if " " in quotedArgs[i]:
quotedArgs[i] = "\"" & quotedArgs[i] & "\""
echo "exec(): ", quotedArgs.join(" ")
if not liveOutput:
result = execCmdEx(quotedArgs.join(" "))
else:
result.output = ""
let process = startProcess(quotedArgs.join(" "),
options={poEvalCommand, poStdErrToStdOut})
var missedEscape = false
while true:
if not process.outputStream.atEnd:
let line = process.outputStream.outputReader(missedEscape)
result.output.add(line)
stdout.write(line)
if line.len() != 0 and line[0] != '\27':
stdout.flushFile()
else:
result.exitCode = process.peekExitCode()
if result.exitCode != -1: break
process.close()
proc processOutput(output: string): seq[string] =
output.strip.splitLines().filter((x: string) => (x.len > 0))
proc inLines(lines: seq[string], word: string): bool =
for i in lines:
if word.normalize in i.normalize: return true
proc hasLine(lines: seq[string], line: string): bool =
for i in lines:
if i.normalize.strip() == line.normalize(): return true
test "can compile getnim":
var args = @["build"]
when defined(release):
args.add "-d:release"
when defined(staticBuild):
args.add "-d:staticBuild"
let (_, exitCode) = exec(args, exe="nimble", global=true, liveOutput=true)
check exitCode == QuitSuccess
test "refuses invalid path":
beginTest()
block:
let (output, exitCode) = exec(getTempDir() / "blahblah")
check exitCode == QuitFailure
check inLines(output.processOutput, "invalid")
check inLines(output.processOutput, "version")
check inLines(output.processOutput, "path")
block:
let (output, exitCode) = exec(getTempDir())
check exitCode == QuitFailure
check inLines(output.processOutput, "no")
check inLines(output.processOutput, "binary")
check inLines(output.processOutput, "found")
test "fails on bad flag":
beginTest()
let (output, exitCode) = exec("--qwetqsdweqwe")
check exitCode == QuitFailure
check inLines(output.processOutput, "unknown")
check inLines(output.processOutput, "flag")
test "can choose #v1.0.0":
beginTest()
block:
let (output, exitCode) = exec("\"#v1.0.0\"", liveOutput=true)
check exitCode == QuitSuccess
check inLines(output.processOutput, "building")
check inLines(output.processOutput, "downloading")
check inLines(output.processOutput, "building tools")
check hasLine(output.processOutput, "switched to nim #v1.0.0")
block:
let (output, exitCode) = exec("\"#v1.0.0\"")
check exitCode == QuitSuccess
check hasLine(output.processOutput, "info: version #v1.0.0 already selected")
# block:
# let (output, exitCode) = exec("--version", exe=nimbleDir / "bin" / "nimble")
# check exitCode == QuitSuccess
# check inLines(output.processOutput, "v0.11.0")
# Verify that we cannot remove currently selected #v1.0.0.
block:
let (output, exitCode) = exec(["remove", "\"#v1.0.0\""], liveOutput=true)
check exitCode == QuitFailure
check inLines(output.processOutput, "Cannot remove current version.")
test "cannot remove not installed v0.16.0":
beginTest()
block:
let (output, exitCode) = exec(["remove", "0.16.0"], liveOutput=true)
check exitCode == QuitFailure
check inLines(output.processOutput, "Version 0.16.0 is not installed.")
when defined(linux):
test "linux binary install":
beginTest()
block:
let (output, exitCode) = exec("1.0.0", liveOutput=true)
check exitCode == QuitSuccess
check inLines(output.processOutput, "downloading")
check inLines(output.processOutput, "already built")
check hasLine(output.processOutput, "switched to nim 1.0.0")
check not dirExists(getnimDir / "toolchains" / "nim-1.0.0" / "c_code")
test "can update devel with git":
beginTest()
block:
let (output, exitCode) = exec(@["devel", "--latest"], liveOutput=true)
check inLines(output.processOutput, "extracting")
check inLines(output.processOutput, "setting")
check inLines(output.processOutput, "latest changes")
check inLines(output.processOutput, "building")
if exitCode != QuitSuccess:
# Let's be lenient here, latest Nim build could fail for any number of
# reasons (HEAD could be broken).
warn("Could not build latest `devel` of Nim, possibly a bug in getnim")
block:
let (output, exitCode) = exec(@["update", "devel", "--latest"], liveOutput=true)
# TODO: Below lines could fail in rare circumstances: if new commit is
# made just after the above tests starts.
# check not inLines(output.processOutput, "extracting")
# check not inLines(output.processOutput, "setting")
# TODO Disabling the above until https://github.com/nim-lang/Nim/pull/18945
# is merged.
check inLines(output.processOutput, "updating")
check inLines(output.processOutput, "latest changes")
check inLines(output.processOutput, "building")
if exitCode != QuitSuccess:
# Let's be lenient here, latest Nim build could fail for any number of
# reasons (HEAD could be broken).
warn("Could not build latest `devel` of Nim, possibly a bug in getnim")
test "can install and update nightlies":
beginTest()
block:
# Install nightly
let (output, exitCode) = exec("devel", liveOutput=true)
# Travis runs into Github API limit
if not inLines(output.processOutput, "unavailable"):
check exitCode == QuitSuccess
check inLines(output.processOutput, "devel from")
check inLines(output.processOutput, "setting")
when not defined(macosx):
if not inLines(output.processOutput, "recent nightly"):
check inLines(output.processOutput, "already built")
check inLines(output.processOutput, "to Nim #devel")
block:
# Update nightly
let (output, exitCode) = exec(@["update", "devel"], liveOutput=true)
# Travis runs into Github API limit
if not inLines(output.processOutput, "unavailable"):
check exitCode == QuitSuccess
check inLines(output.processOutput, "updating")
check inLines(output.processOutput, "devel from")
check inLines(output.processOutput, "setting")
when not defined(macosx):
if not inLines(output.processOutput, "recent nightly"):
check inLines(output.processOutput, "already built")
test "can update self":
# updateSelf() doesn't use options --getnimDir and --nimbleDir. It's used getAppDir().
# This will rewrite $project/bin dir, it's dangerous.
# So, this test copy bin/getnim to test/getnimDir/getnim, and use it.
beginTest()
let testExePath = getnimDir / extractFilename(exePath)
copyFileWithPermissions(exePath, testExePath)
block :
let (output, exitCode) = exec(["update", "self", "--debug", "--force"], exe=testExePath, liveOutput=true)
check exitCode == QuitSuccess
check inLines(output.processOutput, "Info: Updated getnim to version")
test "fails with invalid version":
beginTest()
block:
let (output, exitCode) = exec("\"#version-1.6\"")
check exitCode == QuitFailure
check inLines(output.processOutput, "Version")
check inLines(output.processOutput, "does not exist")
test "can show general informations":
beginTest()
block:
let (_, exitCode) = exec(@["stable"])
check exitCode == QuitSuccess
block:
let (output, exitCode) = exec(@["show"])
check exitCode == QuitSuccess
check inLines(output.processOutput, "Selected:")
check inLines(output.processOutput, "Channel: stable")
check inLines(output.processOutput, "Path: " & getnimDir)
test "can show path":
beginTest()
block:
let (_, exitCode) = exec(@["stable"])
check exitCode == QuitSuccess
block:
let (output, exitCode) = exec(@["show", "path"])
check exitCode == QuitSuccess
echo output.processOutput
check inLines(output.processOutput, getnimDir)