tosproc.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. # test the osproc module
  2. import stdtest/specialpaths
  3. import "../.." / compiler/unittest_light
  4. when defined(case_testfile): # compiled test file for child process
  5. from posix import exitnow
  6. proc c_exit2(code: c_int): void {.importc: "_exit", header: "<unistd.h>".}
  7. import os
  8. var a = 0
  9. proc fun(b = 0) =
  10. a.inc
  11. if a mod 10000000 == 0: # prevents optimizing it away
  12. echo a
  13. fun(b+1)
  14. proc main() =
  15. let args = commandLineParams()
  16. echo (msg: "child binary", pid: getCurrentProcessId())
  17. let arg = args[0]
  18. echo (arg: arg)
  19. case arg
  20. of "exit_0":
  21. if true: quit(0)
  22. of "exitnow_139":
  23. if true: exitnow(139)
  24. of "c_exit2_139":
  25. if true: c_exit2(139)
  26. of "quit_139":
  27. # `exitStatusLikeShell` doesn't distinguish between a process that
  28. # exit(139) and a process that gets killed with `SIGSEGV` because
  29. # 139 = 11 + 128 = SIGSEGV + 128.
  30. # However, as #10249 shows, this leads to bad debugging experience
  31. # when a child process dies with SIGSEGV, leaving no trace of why it
  32. # failed. The shell (and lldb debugger) solves that by inserting a
  33. # helpful msg: `segmentation fault` when it detects a signal killed
  34. # the child.
  35. # todo: expose an API that will show more diagnostic, returning
  36. # (exitCode, signal) instead of just `shellExitCode`.
  37. if true: quit(139)
  38. of "exit_recursion": # stack overflow by infinite recursion
  39. fun()
  40. echo a
  41. of "exit_array": # bad array access
  42. echo args[1]
  43. main()
  44. else:
  45. import os, osproc, strutils, posix
  46. const nim = getCurrentCompilerExe()
  47. block execShellCmdTest:
  48. ## first, compile child program
  49. const sourcePath = currentSourcePath()
  50. let output = buildDir / "D20190111T024543".addFileExt(ExeExt)
  51. let cmd = "$# c -o:$# -d:release -d:case_testfile $#" % [nim, output,
  52. sourcePath]
  53. # we're testing `execShellCmd` so don't rely on it to compile test file
  54. # note: this should be exported in posix.nim
  55. proc c_system(cmd: cstring): cint {.importc: "system",
  56. header: "<stdlib.h>".}
  57. assertEquals c_system(cmd), 0
  58. ## use it
  59. template runTest(arg: string, expected: int) =
  60. echo (arg2: arg, expected2: expected)
  61. assertEquals execShellCmd(output & " " & arg), expected
  62. runTest("exit_0", 0)
  63. runTest("exitnow_139", 139)
  64. runTest("c_exit2_139", 139)
  65. runTest("quit_139", 139)
  66. block execProcessTest:
  67. let dir = parentDir(currentSourcePath())
  68. let (outp, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim"))
  69. doAssert err == 0
  70. let exePath = dir / addFileExt("osproctest", ExeExt)
  71. let outStr1 = execProcess(exePath, workingDir = dir, args = ["foo",
  72. "b A r"], options = {})
  73. doAssert outStr1 == dir & "\nfoo\nb A r\n"
  74. const testDir = "t e st"
  75. createDir(testDir)
  76. doAssert dirExists(testDir)
  77. let outStr2 = execProcess(exePath, workingDir = testDir, args = ["x yz"],
  78. options = {})
  79. doAssert outStr2 == absolutePath(testDir) & "\nx yz\n"
  80. removeDir(testDir)
  81. try:
  82. removeFile(exePath)
  83. except OSError:
  84. discard