TerminalProcessInterpretExitCode.test.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { TerminalProcess } from "../TerminalProcess"
  2. import { execSync } from "child_process"
  3. describe("TerminalProcess.interpretExitCode", () => {
  4. it("should handle undefined exit code", () => {
  5. const result = TerminalProcess.interpretExitCode(undefined)
  6. expect(result).toEqual({ exitCode: undefined })
  7. })
  8. it("should handle normal exit codes (0-127)", () => {
  9. // Test success exit code (0)
  10. let result = TerminalProcess.interpretExitCode(0)
  11. expect(result).toEqual({ exitCode: 0 })
  12. // Test error exit code (1)
  13. result = TerminalProcess.interpretExitCode(1)
  14. expect(result).toEqual({ exitCode: 1 })
  15. // Test arbitrary exit code within normal range
  16. result = TerminalProcess.interpretExitCode(42)
  17. expect(result).toEqual({ exitCode: 42 })
  18. // Test boundary exit code
  19. result = TerminalProcess.interpretExitCode(127)
  20. expect(result).toEqual({ exitCode: 127 })
  21. })
  22. it("should handle signal exit codes (128+)", () => {
  23. // Test SIGINT (Ctrl+C) - 128 + 2 = 130
  24. const result = TerminalProcess.interpretExitCode(130)
  25. expect(result).toEqual({
  26. exitCode: 130,
  27. signal: 2,
  28. signalName: "SIGINT",
  29. coreDumpPossible: false,
  30. })
  31. // Test SIGTERM - 128 + 15 = 143
  32. const resultTerm = TerminalProcess.interpretExitCode(143)
  33. expect(resultTerm).toEqual({
  34. exitCode: 143,
  35. signal: 15,
  36. signalName: "SIGTERM",
  37. coreDumpPossible: false,
  38. })
  39. // Test SIGSEGV (segmentation fault) - 128 + 11 = 139
  40. const resultSegv = TerminalProcess.interpretExitCode(139)
  41. expect(resultSegv).toEqual({
  42. exitCode: 139,
  43. signal: 11,
  44. signalName: "SIGSEGV",
  45. coreDumpPossible: true,
  46. })
  47. })
  48. it("should identify signals that can produce core dumps", () => {
  49. // Core dump possible signals: SIGQUIT(3), SIGILL(4), SIGABRT(6), SIGBUS(7), SIGFPE(8), SIGSEGV(11)
  50. const coreDumpSignals = [3, 4, 6, 7, 8, 11]
  51. for (const signal of coreDumpSignals) {
  52. const exitCode = 128 + signal
  53. const result = TerminalProcess.interpretExitCode(exitCode)
  54. expect(result.coreDumpPossible).toBe(true)
  55. }
  56. // Test a non-core-dump signal
  57. const nonCoreDumpResult = TerminalProcess.interpretExitCode(128 + 1) // SIGHUP
  58. expect(nonCoreDumpResult.coreDumpPossible).toBe(false)
  59. })
  60. it("should handle unknown signals", () => {
  61. // Test an exit code for a signal that's not in our mapping
  62. const result = TerminalProcess.interpretExitCode(128 + 99)
  63. expect(result).toEqual({
  64. exitCode: 128 + 99,
  65. signal: 99,
  66. signalName: "Unknown Signal (99)",
  67. coreDumpPossible: false,
  68. })
  69. })
  70. })
  71. describe("TerminalProcess.interpretExitCode with real commands", () => {
  72. it("should correctly interpret exit code 0 from successful command", () => {
  73. try {
  74. // Run a command that should succeed
  75. execSync("echo test", { stdio: "ignore" })
  76. // If we get here, the command succeeded with exit code 0
  77. const result = TerminalProcess.interpretExitCode(0)
  78. expect(result).toEqual({ exitCode: 0 })
  79. } catch (error: any) {
  80. // This should not happen for a successful command
  81. fail("Command should have succeeded: " + error.message)
  82. }
  83. })
  84. it("should correctly interpret exit code 1 from failed command", () => {
  85. try {
  86. // Run a command that should fail with exit code 1 or 2
  87. execSync("ls /nonexistent_directory", { stdio: "ignore" })
  88. fail("Command should have failed")
  89. } catch (error: any) {
  90. // Verify the exit code is what we expect (can be 1 or 2 depending on the system)
  91. expect(error.status).toBeGreaterThan(0)
  92. expect(error.status).toBeLessThan(128) // Not a signal
  93. const result = TerminalProcess.interpretExitCode(error.status)
  94. expect(result).toEqual({ exitCode: error.status })
  95. }
  96. })
  97. it("should correctly interpret exit code from command with custom exit code", () => {
  98. try {
  99. // Run a command that exits with a specific code
  100. execSync("exit 42", { stdio: "ignore" })
  101. fail("Command should have exited with code 42")
  102. } catch (error: any) {
  103. expect(error.status).toBe(42)
  104. const result = TerminalProcess.interpretExitCode(error.status)
  105. expect(result).toEqual({ exitCode: 42 })
  106. }
  107. })
  108. // Test signal interpretation directly without relying on actual process termination
  109. it("should correctly interpret signal termination codes", () => {
  110. // Test SIGTERM (signal 15)
  111. const sigtermExitCode = 128 + 15
  112. const sigtermResult = TerminalProcess.interpretExitCode(sigtermExitCode)
  113. expect(sigtermResult.signal).toBe(15)
  114. expect(sigtermResult.signalName).toBe("SIGTERM")
  115. expect(sigtermResult.coreDumpPossible).toBe(false)
  116. // Test SIGSEGV (signal 11)
  117. const sigsegvExitCode = 128 + 11
  118. const sigsegvResult = TerminalProcess.interpretExitCode(sigsegvExitCode)
  119. expect(sigsegvResult.signal).toBe(11)
  120. expect(sigsegvResult.signalName).toBe("SIGSEGV")
  121. expect(sigsegvResult.coreDumpPossible).toBe(true)
  122. // Test SIGINT (signal 2)
  123. const sigintExitCode = 128 + 2
  124. const sigintResult = TerminalProcess.interpretExitCode(sigintExitCode)
  125. expect(sigintResult.signal).toBe(2)
  126. expect(sigintResult.signalName).toBe("SIGINT")
  127. expect(sigintResult.coreDumpPossible).toBe(false)
  128. })
  129. })