categories.nim 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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. ## Include for the tester that contains test suites that test special features
  10. ## of the compiler.
  11. # included from tester.nim
  12. # ---------------- ROD file tests ---------------------------------------------
  13. const
  14. rodfilesDir = "tests/rodfiles"
  15. proc delNimCache(filename, options: string) =
  16. for target in low(TTarget)..high(TTarget):
  17. let dir = nimcacheDir(filename, options, target)
  18. try:
  19. removeDir(dir)
  20. except OSError:
  21. echo "[Warning] could not delete: ", dir
  22. proc runRodFiles(r: var TResults, cat: Category, options: string) =
  23. template test(filename: string, clearCacheFirst=false) =
  24. if clearCacheFirst: delNimCache(filename, options)
  25. testSpec r, makeTest(rodfilesDir / filename, options, cat, actionRun)
  26. # test basic recompilation scheme:
  27. test "hallo", true
  28. test "hallo"
  29. when false:
  30. # test incremental type information:
  31. test "hallo2"
  32. # test type converters:
  33. test "aconv", true
  34. test "bconv"
  35. # test G, A, B example from the documentation; test init sections:
  36. test "deada", true
  37. test "deada2"
  38. when false:
  39. # test method generation:
  40. test "bmethods", true
  41. test "bmethods2"
  42. # test generics:
  43. test "tgeneric1", true
  44. test "tgeneric2"
  45. proc compileRodFiles(r: var TResults, cat: Category, options: string) =
  46. template test(filename: untyped, clearCacheFirst=true) =
  47. if clearCacheFirst: delNimCache(filename, options)
  48. testSpec r, makeTest(rodfilesDir / filename, options, cat)
  49. # test DLL interfacing:
  50. test "gtkex1", true
  51. test "gtkex2"
  52. # --------------------- flags tests -------------------------------------------
  53. proc flagTests(r: var TResults, cat: Category, options: string) =
  54. # --genscript
  55. const filename = "tests"/"flags"/"tgenscript"
  56. const genopts = " --genscript"
  57. let nimcache = nimcacheDir(filename, genopts, targetC)
  58. testSpec r, makeTest(filename, genopts, cat)
  59. when defined(windows):
  60. testExec r, makeTest(filename, " cmd /c cd " & nimcache &
  61. " && compile_tgenscript.bat", cat)
  62. elif defined(posix):
  63. testExec r, makeTest(filename, " sh -c \"cd " & nimcache &
  64. " && sh compile_tgenscript.sh\"", cat)
  65. # Run
  66. testExec r, makeTest(filename, " " & nimcache / "tgenscript", cat)
  67. # --------------------- DLL generation tests ----------------------------------
  68. proc safeCopyFile(src, dest: string) =
  69. try:
  70. copyFile(src, dest)
  71. except OSError:
  72. echo "[Warning] could not copy: ", src, " to ", dest
  73. proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
  74. const rpath = when defined(macosx):
  75. " --passL:-rpath --passL:@loader_path"
  76. else:
  77. ""
  78. testSpec c, makeTest("lib/nimrtl.nim",
  79. options & " --app:lib -d:createNimRtl --threads:on", cat)
  80. testSpec c, makeTest("tests/dll/server.nim",
  81. options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat)
  82. when defined(Windows):
  83. # windows looks in the dir of the exe (yay!):
  84. var nimrtlDll = DynlibFormat % "nimrtl"
  85. safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
  86. else:
  87. # posix relies on crappy LD_LIBRARY_PATH (ugh!):
  88. const libpathenv = when defined(haiku):
  89. "LIBRARY_PATH"
  90. else:
  91. "LD_LIBRARY_PATH"
  92. var libpath = getEnv(libpathenv).string
  93. # Temporarily add the lib directory to LD_LIBRARY_PATH:
  94. putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: ""))
  95. defer: putEnv(libpathenv, libpath)
  96. var nimrtlDll = DynlibFormat % "nimrtl"
  97. safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
  98. testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl --threads:on" & rpath,
  99. cat, actionRun)
  100. proc dllTests(r: var TResults, cat: Category, options: string) =
  101. # dummy compile result:
  102. var c = initResults()
  103. runBasicDLLTest c, r, cat, options
  104. runBasicDLLTest c, r, cat, options & " -d:release"
  105. when not defined(windows):
  106. # still cannot find a recent Windows version of boehm.dll:
  107. runBasicDLLTest c, r, cat, options & " --gc:boehm"
  108. runBasicDLLTest c, r, cat, options & " -d:release --gc:boehm"
  109. # ------------------------------ GC tests -------------------------------------
  110. proc gcTests(r: var TResults, cat: Category, options: string) =
  111. template testWithNone(filename: untyped) =
  112. testSpec r, makeTest("tests/gc" / filename, options &
  113. " --gc:none", cat, actionRun)
  114. testSpec r, makeTest("tests/gc" / filename, options &
  115. " -d:release --gc:none", cat, actionRun)
  116. template testWithoutMs(filename: untyped) =
  117. testSpec r, makeTest("tests/gc" / filename, options, cat, actionRun)
  118. testSpec r, makeTest("tests/gc" / filename, options &
  119. " -d:release", cat, actionRun)
  120. testSpec r, makeTest("tests/gc" / filename, options &
  121. " -d:release -d:useRealtimeGC", cat, actionRun)
  122. template testWithoutBoehm(filename: untyped) =
  123. testWithoutMs filename
  124. testSpec r, makeTest("tests/gc" / filename, options &
  125. " --gc:markAndSweep", cat, actionRun)
  126. testSpec r, makeTest("tests/gc" / filename, options &
  127. " -d:release --gc:markAndSweep", cat, actionRun)
  128. template test(filename: untyped) =
  129. testWithoutBoehm filename
  130. when not defined(windows) and not defined(android):
  131. # AR: cannot find any boehm.dll on the net, right now, so disabled
  132. # for windows:
  133. testSpec r, makeTest("tests/gc" / filename, options &
  134. " --gc:boehm", cat, actionRun)
  135. testSpec r, makeTest("tests/gc" / filename, options &
  136. " -d:release --gc:boehm", cat, actionRun)
  137. testWithoutBoehm "foreign_thr"
  138. test "gcemscripten"
  139. test "growobjcrash"
  140. test "gcbench"
  141. test "gcleak"
  142. test "gcleak2"
  143. testWithoutBoehm "gctest"
  144. testWithNone "gctest"
  145. test "gcleak3"
  146. test "gcleak4"
  147. # Disabled because it works and takes too long to run:
  148. #test "gcleak5"
  149. testWithoutBoehm "weakrefs"
  150. test "cycleleak"
  151. testWithoutBoehm "closureleak"
  152. testWithoutMs "refarrayleak"
  153. testWithoutBoehm "tlists"
  154. testWithoutBoehm "thavlak"
  155. test "stackrefleak"
  156. test "cyclecollector"
  157. proc longGCTests(r: var TResults, cat: Category, options: string) =
  158. when defined(windows):
  159. let cOptions = "-ldl -DWIN"
  160. else:
  161. let cOptions = "-ldl"
  162. var c = initResults()
  163. # According to ioTests, this should compile the file
  164. testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile)
  165. testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun)
  166. testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun)
  167. # ------------------------- threading tests -----------------------------------
  168. proc threadTests(r: var TResults, cat: Category, options: string) =
  169. template test(filename: untyped) =
  170. testSpec r, makeTest(filename, options, cat, actionRun)
  171. testSpec r, makeTest(filename, options & " -d:release", cat, actionRun)
  172. testSpec r, makeTest(filename, options & " --tlsEmulation:on", cat, actionRun)
  173. for t in os.walkFiles("tests/threads/t*.nim"):
  174. test(t)
  175. # ------------------------- IO tests ------------------------------------------
  176. proc ioTests(r: var TResults, cat: Category, options: string) =
  177. # We need readall_echo to be compiled for this test to run.
  178. # dummy compile result:
  179. var c = initResults()
  180. testSpec c, makeTest("tests/system/helpers/readall_echo", options, cat)
  181. testSpec r, makeTest("tests/system/tio", options, cat)
  182. # ------------------------- async tests ---------------------------------------
  183. proc asyncTests(r: var TResults, cat: Category, options: string) =
  184. template test(filename: untyped) =
  185. testSpec r, makeTest(filename, options, cat)
  186. for t in os.walkFiles("tests/async/t*.nim"):
  187. test(t)
  188. # ------------------------- debugger tests ------------------------------------
  189. proc debuggerTests(r: var TResults, cat: Category, options: string) =
  190. testNoSpec r, makeTest("tools/nimgrep", options & " --debugger:on", cat)
  191. # ------------------------- JS tests ------------------------------------------
  192. proc jsTests(r: var TResults, cat: Category, options: string) =
  193. template test(filename: untyped) =
  194. testSpec r, makeTest(filename, options & " -d:nodejs", cat,
  195. actionRun), targetJS
  196. testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat,
  197. actionRun), targetJS
  198. for t in os.walkFiles("tests/js/t*.nim"):
  199. test(t)
  200. for testfile in ["exception/texceptions", "exception/texcpt1",
  201. "exception/texcsub", "exception/tfinally",
  202. "exception/tfinally2", "exception/tfinally3",
  203. "exception/tunhandledexc",
  204. "actiontable/tactiontable", "method/tmultim1",
  205. "method/tmultim3", "method/tmultim4",
  206. "varres/tvarres0", "varres/tvarres3", "varres/tvarres4",
  207. "varres/tvartup", "misc/tints", "misc/tunsignedinc",
  208. "async/tjsandnativeasync"]:
  209. test "tests/" & testfile & ".nim"
  210. for testfile in ["strutils", "json", "random", "times", "logging"]:
  211. test "lib/pure/" & testfile & ".nim"
  212. # ------------------------- nim in action -----------
  213. proc testNimInAction(r: var TResults, cat: Category, options: string) =
  214. let options = options & " --nilseqs:on"
  215. template test(filename: untyped, action: untyped) =
  216. testSpec r, makeTest(filename, options, cat, action)
  217. template testJS(filename: untyped) =
  218. testSpec r, makeTest(filename, options, cat, actionCompile), targetJS
  219. template testCPP(filename: untyped) =
  220. testSpec r, makeTest(filename, options, cat, actionCompile), targetCPP
  221. let tests = [
  222. "niminaction/Chapter1/various1",
  223. "niminaction/Chapter2/various2",
  224. "niminaction/Chapter2/resultaccept",
  225. "niminaction/Chapter2/resultreject",
  226. "niminaction/Chapter2/explicit_discard",
  227. "niminaction/Chapter2/no_def_eq",
  228. "niminaction/Chapter2/no_iterator",
  229. "niminaction/Chapter2/no_seq_type",
  230. "niminaction/Chapter3/ChatApp/src/server",
  231. "niminaction/Chapter3/ChatApp/src/client",
  232. "niminaction/Chapter3/various3",
  233. "niminaction/Chapter6/WikipediaStats/concurrency_regex",
  234. "niminaction/Chapter6/WikipediaStats/concurrency",
  235. "niminaction/Chapter6/WikipediaStats/naive",
  236. "niminaction/Chapter6/WikipediaStats/parallel_counts",
  237. "niminaction/Chapter6/WikipediaStats/race_condition",
  238. "niminaction/Chapter6/WikipediaStats/sequential_counts",
  239. "niminaction/Chapter6/WikipediaStats/unguarded_access",
  240. "niminaction/Chapter7/Tweeter/src/tweeter",
  241. "niminaction/Chapter7/Tweeter/src/createDatabase",
  242. "niminaction/Chapter7/Tweeter/tests/database_test",
  243. "niminaction/Chapter8/sdl/sdl_test"
  244. ]
  245. # Verify that the files have not been modified. Death shall fall upon
  246. # whoever edits these hashes without dom96's permission, j/k. But please only
  247. # edit when making a conscious breaking change, also please try to make your
  248. # commit message clear and notify me so I can easily compile an errata later.
  249. var testHashes: seq[string] = @[]
  250. for test in tests:
  251. testHashes.add(getMD5(readFile("tests" / test.addFileExt("nim")).string))
  252. const refHashes = @[
  253. "51afdfa84b3ca3d810809d6c4e5037ba", "30f07e4cd5eaec981f67868d4e91cfcf",
  254. "d14e7c032de36d219c9548066a97e846", "2e40bfd5daadb268268727da91bb4e81",
  255. "c5d3853ed0aba04bf6d35ba28a98dca0", "058603145ff92d46c009006b06e5b228",
  256. "7b94a029b94ddb7efafddd546c965ff6", "586d74514394e49f2370dfc01dd9e830",
  257. "e1901837b757c9357dc8d259fd0ef0f6", "097670c7ae12e825debaf8ec3995227b",
  258. "a8cb7b78cc78d28535ab467361db5d6e", "bfaec2816a1848991b530c1ad17a0184",
  259. "47cb71bb4c1198d6d29cdbee05aa10b9", "87e4436809f9d73324cfc4f57f116770",
  260. "7b7db5cddc8cf8fa9b6776eef1d0a31d", "e6e40219f0f2b877869b738737b7685e",
  261. "6532ee87d819f2605a443d5e94f9422a", "9a8fe78c588d08018843b64b57409a02",
  262. "03a801275b8b76b4170c870cd0da079d", "20bb7d3e2d38d43b0cb5fcff4909a4a8",
  263. "af6844598f534fab6942abfa4dfe9ab2", "2a7a17f84f6503d9bc89a5ab8feea127"
  264. ]
  265. doAssert testHashes == refHashes, "Nim in Action tests were changed."
  266. # Run the tests.
  267. for testfile in tests:
  268. test "tests/" & testfile & ".nim", actionCompile
  269. let jsFile = "tests/niminaction/Chapter8/canvas/canvas_test.nim"
  270. testJS jsFile
  271. let cppFile = "tests/niminaction/Chapter8/sfml/sfml_test.nim"
  272. testCPP cppFile
  273. # ------------------------- manyloc -------------------------------------------
  274. #proc runSpecialTests(r: var TResults, options: string) =
  275. # for t in ["lib/packages/docutils/highlite"]:
  276. # testSpec(r, t, options)
  277. proc findMainFile(dir: string): string =
  278. # finds the file belonging to ".nim.cfg"; if there is no such file
  279. # it returns the some ".nim" file if there is only one:
  280. const cfgExt = ".nim.cfg"
  281. result = ""
  282. var nimFiles = 0
  283. for kind, file in os.walkDir(dir):
  284. if kind == pcFile:
  285. if file.endsWith(cfgExt): return file[.. ^(cfgExt.len+1)] & ".nim"
  286. elif file.endsWith(".nim"):
  287. if result.len == 0: result = file
  288. inc nimFiles
  289. if nimFiles != 1: result.setlen(0)
  290. proc manyLoc(r: var TResults, cat: Category, options: string) =
  291. for kind, dir in os.walkDir("tests/manyloc"):
  292. if kind == pcDir:
  293. when defined(windows):
  294. if dir.endsWith"nake": continue
  295. if dir.endsWith"named_argument_bug": continue
  296. let mainfile = findMainFile(dir)
  297. if mainfile != "":
  298. testNoSpec r, makeTest(mainfile, options, cat)
  299. proc compileExample(r: var TResults, pattern, options: string, cat: Category) =
  300. for test in os.walkFiles(pattern):
  301. testNoSpec r, makeTest(test, options, cat)
  302. proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
  303. for test in os.walkFiles(pattern):
  304. let name = extractFilename(test)
  305. if name notin disabledFiles:
  306. let contents = readFile(test).string
  307. if contents.contains("when isMainModule"):
  308. testSpec r, makeTest(test, options, cat, actionRunNoSpec)
  309. else:
  310. testNoSpec r, makeTest(test, options, cat, actionCompile)
  311. # ----------------------------- nimble ----------------------------------------
  312. type PackageFilter = enum
  313. pfCoreOnly
  314. pfExtraOnly
  315. pfAll
  316. var nimbleDir = getEnv("NIMBLE_DIR").string
  317. if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
  318. let
  319. nimbleExe = findExe("nimble")
  320. #packageDir = nimbleDir / "pkgs" # not used
  321. packageIndex = nimbleDir / "packages.json"
  322. proc waitForExitEx(p: Process): int =
  323. var outp = outputStream(p)
  324. var line = newStringOfCap(120).TaintedString
  325. while true:
  326. if outp.readLine(line):
  327. discard
  328. else:
  329. result = peekExitCode(p)
  330. if result != -1: break
  331. close(p)
  332. proc getPackageDir(package: string): string =
  333. ## TODO - Replace this with dom's version comparison magic.
  334. var commandOutput = execCmdEx("nimble path $#" % package)
  335. if commandOutput.exitCode != QuitSuccess:
  336. return ""
  337. else:
  338. result = commandOutput[0].string
  339. iterator listPackages(filter: PackageFilter): tuple[name, url: string] =
  340. let packageList = parseFile(packageIndex)
  341. for package in packageList.items():
  342. let
  343. name = package["name"].str
  344. url = package["url"].str
  345. isCorePackage = "nim-lang" in normalize(url)
  346. case filter:
  347. of pfCoreOnly:
  348. if isCorePackage:
  349. yield (name, url)
  350. of pfExtraOnly:
  351. if not isCorePackage:
  352. yield (name, url)
  353. of pfAll:
  354. yield (name, url)
  355. proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
  356. if nimbleExe == "":
  357. echo("[Warning] - Cannot run nimble tests: Nimble binary not found.")
  358. return
  359. if execCmd("$# update" % nimbleExe) == QuitFailure:
  360. echo("[Warning] - Cannot run nimble tests: Nimble update failed.")
  361. return
  362. let packageFileTest = makeTest("PackageFileParsed", "", cat)
  363. try:
  364. for name, url in listPackages(filter):
  365. var test = makeTest(name, "", cat)
  366. echo(url)
  367. let
  368. installProcess = startProcess(nimbleExe, "", ["install", "-y", name])
  369. installStatus = waitForExitEx(installProcess)
  370. installProcess.close
  371. if installStatus != QuitSuccess:
  372. r.addResult(test, targetC, "", "", reInstallFailed)
  373. continue
  374. let
  375. buildPath = getPackageDir(name).strip
  376. buildProcess = startProcess(nimbleExe, buildPath, ["build"])
  377. buildStatus = waitForExitEx(buildProcess)
  378. buildProcess.close
  379. if buildStatus != QuitSuccess:
  380. r.addResult(test, targetC, "", "", reBuildFailed)
  381. r.addResult(test, targetC, "", "", reSuccess)
  382. r.addResult(packageFileTest, targetC, "", "", reSuccess)
  383. except JsonParsingError:
  384. echo("[Warning] - Cannot run nimble tests: Invalid package file.")
  385. r.addResult(packageFileTest, targetC, "", "", reBuildFailed)
  386. # ----------------------------------------------------------------------------
  387. const AdditionalCategories = ["debugger", "examples", "lib"]
  388. proc `&.?`(a, b: string): string =
  389. # candidate for the stdlib?
  390. result = if b.startswith(a): b else: a & b
  391. #proc `&?.`(a, b: string): string = # not used
  392. # candidate for the stdlib?
  393. #result = if a.endswith(b): a else: a & b
  394. proc processSingleTest(r: var TResults, cat: Category, options, test: string) =
  395. let test = "tests" & DirSep &.? cat.string / test
  396. let target = if cat.string.normalize == "js": targetJS else: targetC
  397. if existsFile(test): testSpec r, makeTest(test, options, cat), target
  398. else: echo "[Warning] - ", test, " test does not exist"
  399. proc processCategory(r: var TResults, cat: Category, options: string) =
  400. case cat.string.normalize
  401. of "rodfiles":
  402. when false:
  403. compileRodFiles(r, cat, options)
  404. runRodFiles(r, cat, options)
  405. of "js":
  406. # only run the JS tests on Windows or Linux because Travis is bad
  407. # and other OSes like Haiku might lack nodejs:
  408. if not defined(linux) and isTravis:
  409. discard
  410. else:
  411. jsTests(r, cat, options)
  412. of "dll":
  413. dllTests(r, cat, options)
  414. of "flags":
  415. flagTests(r, cat, options)
  416. of "gc":
  417. gcTests(r, cat, options)
  418. of "longgc":
  419. longGCTests(r, cat, options)
  420. of "debugger":
  421. debuggerTests(r, cat, options)
  422. of "manyloc":
  423. manyLoc r, cat, options
  424. of "threads":
  425. threadTests r, cat, options & " --threads:on"
  426. of "io":
  427. ioTests r, cat, options
  428. of "async":
  429. asyncTests r, cat, options
  430. of "lib":
  431. testStdlib(r, "lib/pure/*.nim", options, cat)
  432. testStdlib(r, "lib/packages/docutils/highlite", options, cat)
  433. of "examples":
  434. compileExample(r, "examples/*.nim", options, cat)
  435. compileExample(r, "examples/gtk/*.nim", options, cat)
  436. compileExample(r, "examples/talk/*.nim", options, cat)
  437. of "nimble-core":
  438. testNimblePackages(r, cat, pfCoreOnly)
  439. of "nimble-extra":
  440. testNimblePackages(r, cat, pfExtraOnly)
  441. of "nimble-all":
  442. testNimblePackages(r, cat, pfAll)
  443. of "niminaction":
  444. testNimInAction(r, cat, options)
  445. of "untestable":
  446. # We can't test it because it depends on a third party.
  447. discard # TODO: Move untestable tests to someplace else, i.e. nimble repo.
  448. else:
  449. var testsRun = 0
  450. for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
  451. testSpec r, makeTest(name, options, cat)
  452. inc testsRun
  453. if testsRun == 0:
  454. echo "[Warning] - Invalid category specified \"", cat.string, "\", no tests were run"