specs.nim 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #
  2. #
  3. # Nim Tester
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. import parseutils, strutils, os, osproc, streams, parsecfg
  10. var compilerPrefix* = "compiler" / "nim "
  11. proc cmdTemplate*(): string =
  12. compilerPrefix & "$target --lib:lib --hints:on -d:testing $options $file"
  13. type
  14. TTestAction* = enum
  15. actionCompile = "compile"
  16. actionRun = "run"
  17. actionReject = "reject"
  18. actionRunNoSpec = "runNoSpec"
  19. TResultEnum* = enum
  20. reNimcCrash, # nim compiler seems to have crashed
  21. reMsgsDiffer, # error messages differ
  22. reFilesDiffer, # expected and given filenames differ
  23. reLinesDiffer, # expected and given line numbers differ
  24. reOutputsDiffer,
  25. reExitcodesDiffer,
  26. reInvalidPeg,
  27. reCodegenFailure,
  28. reCodeNotFound,
  29. reExeNotFound,
  30. reInstallFailed # package installation failed
  31. reBuildFailed # package building failed
  32. reIgnored, # test is ignored
  33. reSuccess # test was successful
  34. TTarget* = enum
  35. targetC = "C"
  36. targetCpp = "C++"
  37. targetObjC = "ObjC"
  38. targetJS = "JS"
  39. TSpec* = object
  40. action*: TTestAction
  41. file*, cmd*: string
  42. outp*: string
  43. line*, column*: int
  44. tfile*: string
  45. tline*, tcolumn*: int
  46. exitCode*: int
  47. msg*: string
  48. ccodeCheck*: string
  49. maxCodeSize*: int
  50. err*: TResultEnum
  51. substr*, sortoutput*: bool
  52. targets*: set[TTarget]
  53. nimout*: string
  54. const
  55. targetToExt*: array[TTarget, string] = ["c", "cpp", "m", "js"]
  56. targetToCmd*: array[TTarget, string] = ["c", "cpp", "objc", "js"]
  57. when not declared(parseCfgBool):
  58. # candidate for the stdlib:
  59. proc parseCfgBool(s: string): bool =
  60. case normalize(s)
  61. of "y", "yes", "true", "1", "on": result = true
  62. of "n", "no", "false", "0", "off": result = false
  63. else: raise newException(ValueError, "cannot interpret as a bool: " & s)
  64. proc extractSpec(filename: string): string =
  65. const tripleQuote = "\"\"\""
  66. var x = readFile(filename).string
  67. var a = x.find(tripleQuote)
  68. var b = x.find(tripleQuote, a+3)
  69. # look for """ only in the first section
  70. if a >= 0 and b > a and a < 40:
  71. result = x.substr(a+3, b-1).replace("'''", tripleQuote)
  72. else:
  73. #echo "warning: file does not contain spec: " & filename
  74. result = ""
  75. when not defined(nimhygiene):
  76. {.pragma: inject.}
  77. template parseSpecAux(fillResult: untyped) =
  78. var ss = newStringStream(extractSpec(filename))
  79. var p {.inject.}: CfgParser
  80. open(p, ss, filename, 1)
  81. while true:
  82. var e {.inject.} = next(p)
  83. case e.kind
  84. of cfgEof: break
  85. of cfgSectionStart, cfgOption, cfgError:
  86. echo ignoreMsg(p, e)
  87. of cfgKeyValuePair:
  88. fillResult
  89. close(p)
  90. proc specDefaults*(result: var TSpec) =
  91. result.msg = ""
  92. result.outp = ""
  93. result.nimout = ""
  94. result.ccodeCheck = ""
  95. result.cmd = cmdTemplate()
  96. result.line = 0
  97. result.column = 0
  98. result.tfile = ""
  99. result.tline = 0
  100. result.tcolumn = 0
  101. result.maxCodeSize = 0
  102. proc parseTargets*(value: string): set[TTarget] =
  103. for v in value.normalize.split:
  104. case v
  105. of "c": result.incl(targetC)
  106. of "cpp", "c++": result.incl(targetCpp)
  107. of "objc": result.incl(targetObjC)
  108. of "js": result.incl(targetJS)
  109. else: echo "target ignored: " & v
  110. proc parseSpec*(filename: string): TSpec =
  111. specDefaults(result)
  112. result.file = filename
  113. parseSpecAux:
  114. case normalize(e.key)
  115. of "action":
  116. case e.value.normalize
  117. of "compile": result.action = actionCompile
  118. of "run": result.action = actionRun
  119. of "reject": result.action = actionReject
  120. else: echo ignoreMsg(p, e)
  121. of "file": result.file = e.value
  122. of "line": discard parseInt(e.value, result.line)
  123. of "column": discard parseInt(e.value, result.column)
  124. of "tfile": result.tfile = e.value
  125. of "tline": discard parseInt(e.value, result.tline)
  126. of "tcolumn": discard parseInt(e.value, result.tcolumn)
  127. of "output":
  128. result.action = actionRun
  129. result.outp = e.value
  130. of "outputsub":
  131. result.action = actionRun
  132. result.outp = e.value
  133. result.substr = true
  134. of "sortoutput":
  135. result.sortoutput = parseCfgBool(e.value)
  136. of "exitcode":
  137. discard parseInt(e.value, result.exitCode)
  138. of "msg":
  139. result.msg = e.value
  140. if result.action != actionRun:
  141. result.action = actionCompile
  142. of "errormsg":
  143. result.msg = e.value
  144. result.action = actionReject
  145. of "nimout":
  146. result.nimout = e.value
  147. of "disabled":
  148. case e.value.normalize
  149. of "y", "yes", "true", "1", "on": result.err = reIgnored
  150. of "n", "no", "false", "0", "off": discard
  151. of "win", "windows":
  152. when defined(windows): result.err = reIgnored
  153. of "linux":
  154. when defined(linux): result.err = reIgnored
  155. of "bsd":
  156. when defined(bsd): result.err = reIgnored
  157. of "macosx":
  158. when defined(macosx): result.err = reIgnored
  159. of "unix":
  160. when defined(unix): result.err = reIgnored
  161. of "posix":
  162. when defined(posix): result.err = reIgnored
  163. else:
  164. raise newException(ValueError, "cannot interpret as a bool: " & e.value)
  165. of "cmd":
  166. if e.value.startsWith("nim "):
  167. result.cmd = compilerPrefix & e.value[4..^1]
  168. else:
  169. result.cmd = e.value
  170. of "ccodecheck": result.ccodeCheck = e.value
  171. of "maxcodesize": discard parseInt(e.value, result.maxCodeSize)
  172. of "target", "targets":
  173. for v in e.value.normalize.split:
  174. case v
  175. of "c": result.targets.incl(targetC)
  176. of "cpp", "c++": result.targets.incl(targetCpp)
  177. of "objc": result.targets.incl(targetObjC)
  178. of "js": result.targets.incl(targetJS)
  179. else: echo ignoreMsg(p, e)
  180. else: echo ignoreMsg(p, e)