tquickstart.nim
1 # NimYAML - YAML implementation in Nim 2 # (c) Copyright 2015-2023 Felix Krause 3 # 4 # See the file "copying.txt", included in this 5 # distribution, for details about the copyright. 6 7 import unittest, os, osproc, macros, strutils, streams 8 9 const baseDir = parentDir(staticExec("pwd")) 10 let (nimPathRaw, nimPathRet) = 11 execCmdEx("which nim", {poStdErrToStdOut, poUsePath}) 12 if nimPathRet != 0: quit "could not locate nim executable:\n" & nimPathRaw 13 let nimPath = 14 if nimPathRaw[0] == '/': nimPathRaw.strip else: baseDir / nimPathRaw.strip 15 16 proc inputTest(basePath, path: string): bool = 17 let 18 absolutePath = basePath / path 19 inFileOrig = absolutePath / "01-in.yaml" 20 inFileDest = absolutePath / "in.yaml" 21 codeFileOrig = absolutePath / "00-code.nim" 22 codeFileDest = absolutePath / "code.nim" 23 exeFileDest = when defined(windows): absolutePath / "code.exe" else: 24 absolutePath / "code" 25 copyFile(inFileOrig, inFileDest) 26 copyFile(codeFileOrig, codeFileDest) 27 defer: 28 removeFile(inFileDest) 29 removeFile(codeFileDest) 30 var process = startProcess(nimPath & " c --hints:off -p:" & escape(basePath) & 31 " code.nim", absolutePath, [], nil, {poStdErrToStdOut, poEvalCommand}) 32 defer: 33 process.close() 34 if process.waitForExit() != 0: 35 echo "compiler output:" 36 echo "================\n" 37 echo process.outputStream().readAll() 38 result = false 39 else: 40 defer: removeFile(exeFileDest) 41 process.close() 42 process = startProcess(absolutePath / "code", absolutePath, [], nil, 43 {poStdErrToStdOut, poEvalCommand}) 44 if process.waitForExit() != 0: 45 echo "executable output:" 46 echo "==================\n" 47 echo process.outputStream().readAll() 48 result = false 49 else: result = true 50 51 proc outputTest(basePath, path: string): bool = 52 let 53 absolutePath = basePath / path 54 codeFileOrig = absolutePath / "00-code.nim" 55 codeFileDest = absolutePath / "code.nim" 56 exeFileDest = when defined(windows): absolutePath / "code.exe" else: 57 absolutePath / "code" 58 outFileExpected = absolutePath / "01-out.yaml" 59 outFileActual = absolutePath / "out.yaml" 60 copyFile(codeFileOrig, codeFileDest) 61 defer: removeFile(codeFileDest) 62 var process = startProcess(nimPath & " c --hints:off -p:" & escape(basePath) & 63 " code.nim", absolutePath, [], nil, {poStdErrToStdOut, poEvalCommand}) 64 defer: process.close() 65 if process.waitForExit() != 0: 66 echo "compiler output:" 67 echo "================\n" 68 echo process.outputStream().readAll() 69 result = false 70 else: 71 defer: removeFile(exeFileDest) 72 process.close() 73 process = startProcess(absolutePath / "code", absolutePath, [], nil, 74 {poStdErrToStdOut, poEvalCommand}) 75 if process.waitForExit() != 0: 76 echo "executable output:" 77 echo "==================\n" 78 echo process.outputStream().readAll() 79 result = false 80 else: 81 defer: removeFile(outFileActual) 82 var 83 expected = open(outFileExpected, fmRead) 84 actual = open(outFileActual, fmRead) 85 lineNumber = 1 86 defer: 87 expected.close() 88 actual.close() 89 var 90 expectedLine = "" 91 actualLine = "" 92 while true: 93 if expected.readLine(expectedLine): 94 if actual.readLine(actualLine): 95 if expectedLine != actualLine: 96 echo "difference at line #", lineNumber, ':' 97 echo "expected: ", escape(expectedLine) 98 echo " actual: ", escape(actualLine) 99 return false 100 else: 101 echo "actual output has fewer lines than expected; ", 102 "first missing line: #", lineNumber 103 echo "expected: ", escape(expectedLine) 104 return false 105 else: 106 if actual.readLine(actualLine): 107 echo "actual output has more lines than expected; ", 108 "first unexpected line: #", lineNumber 109 echo "content: ", escape(actualLine) 110 return false 111 else: break 112 lineNumber.inc() 113 result = true 114 115 proc testsFor(path: string, root: bool = true, titlePrefix: string = ""): 116 NimNode {.compileTime.} = 117 result = newStmtList() 118 let 119 title = titlePrefix & slurp(baseDir / path / "title").splitLines()[0] 120 if fileExists(path / "00-code.nim"): 121 var test = newCall("test", newLit(title)) 122 if fileExists(path / "01-in.yaml"): 123 test.add(newCall("doAssert", newCall("inputTest", newLit(baseDir), 124 newLit(path)))) 125 elif fileExists(path / "01-out.yaml"): 126 test.add(newCall("doAssert", newCall("outputTest", newLit(baseDir), 127 newLit(path)))) 128 else: 129 error("Error: neither 01-in.yaml nor 01-out.yaml exists in " & path & '!') 130 result.add(test) 131 for kind, childPath in walkDir(path): 132 if kind == pcDir: 133 if childPath != path / "nimcache": 134 result.add(testsFor(childPath, false, if root: "" else: title & ' ')) 135 if root: 136 result = newCall("suite", newLit(title), result) 137 138 macro genTests(): untyped = testsFor("doc/snippets/quickstart") 139 140 genTests()