You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

command_line.rb 3.9 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. require 'rspec/expectations'
  2. require 'rspec/mocks'
  3. require 'rake'
  4. require 'cucumber/rake/task'
  5. class MockKernel
  6. attr_reader :exit_status
  7. def exit(status)
  8. @exit_status = status
  9. status unless status.zero?
  10. end
  11. end
  12. class CommandLine
  13. include ::RSpec::Mocks::ExampleMethods
  14. def initialize
  15. ::RSpec::Mocks.setup
  16. @stdout = StringIO.new
  17. @stderr = StringIO.new
  18. @kernel = MockKernel.new
  19. end
  20. def stderr
  21. @stderr.string
  22. end
  23. def stdout
  24. @stdout.string
  25. end
  26. def all_output
  27. [stdout, stderr].reject(&:empty?).join("\n")
  28. end
  29. def exit_status
  30. @kernel.exit_status || 0
  31. end
  32. def capture_stdout
  33. capture_stream($stdout, @stdout)
  34. capture_stream($stderr, @stderr)
  35. yield
  36. end
  37. def destroy_mocks
  38. ::RSpec::Mocks.verify
  39. ensure
  40. ::RSpec::Mocks.teardown
  41. end
  42. private
  43. def capture_stream(stream, redirect)
  44. allow(stream)
  45. .to receive(:puts)
  46. .and_wrap_original do |_, *args|
  47. redirect.puts(*args)
  48. end
  49. allow(stream)
  50. .to receive(:print)
  51. .and_wrap_original do |_, *args|
  52. redirect.print(*args)
  53. end
  54. allow(stream)
  55. .to receive(:flush)
  56. .and_wrap_original do |_, *args|
  57. redirect.flush(*args)
  58. end
  59. end
  60. end
  61. class CucumberCommand < CommandLine
  62. attr_reader :args
  63. def execute(args)
  64. @args = args
  65. argument_list = make_arg_list(args)
  66. Cucumber::Cli::Main.new(
  67. argument_list,
  68. @stdout,
  69. @stderr,
  70. @kernel
  71. ).execute!
  72. end
  73. private
  74. def make_arg_list(args)
  75. index = -1
  76. args.split(/'|"/).map do |chunk|
  77. index += 1
  78. index.even? ? chunk.split(' ') : chunk
  79. end.flatten
  80. end
  81. end
  82. class RubyCommand < CommandLine
  83. def execute(file)
  84. capture_stdout { require file }
  85. rescue RuntimeError
  86. # no-op: this is raised when Cucumber fails
  87. rescue SystemExit
  88. # No-op: well, we are supposed to exit the rake task
  89. rescue StandardError
  90. @kernel.exit(1)
  91. end
  92. end
  93. class RakeCommand < CommandLine
  94. def execute(task)
  95. allow_any_instance_of(Cucumber::Rake::Task)
  96. .to receive(:fork)
  97. .and_return(false)
  98. allow(Cucumber::Cli::Main)
  99. .to receive(:execute)
  100. .and_wrap_original do |_, *args|
  101. Cucumber::Cli::Main.new(
  102. args[0],
  103. @stdout,
  104. @stderr,
  105. @kernel
  106. ).execute!
  107. end
  108. Rake.with_application do |rake|
  109. rake.load_rakefile
  110. capture_stdout { rake[task.strip].invoke }
  111. end
  112. rescue RuntimeError
  113. # no-op: this is raised when Cucumber fails
  114. rescue SystemExit
  115. # No-op: well, we are supposed to exit the rake task
  116. end
  117. end
  118. module CLIWorld
  119. def execute_cucumber(args)
  120. execute_command(CucumberCommand, args)
  121. end
  122. def execute_extra_cucumber(args)
  123. execute_extra_command(CucumberCommand, args)
  124. end
  125. def execute_ruby(filename)
  126. execute_command(RubyCommand, "#{Dir.pwd}/#{filename}")
  127. end
  128. def execute_rake(task)
  129. execute_command(RakeCommand, task)
  130. end
  131. def execute_command(cls, args)
  132. @command_line = cls.new
  133. @command_line.execute(args)
  134. end
  135. def execute_extra_command(cls, args)
  136. @extra_commands = []
  137. @extra_commands << cls.new
  138. @extra_commands.last.execute(args)
  139. end
  140. def command_line
  141. @command_line
  142. end
  143. def last_extra_command
  144. @extra_commands&.last
  145. end
  146. end
  147. World(CLIWorld)
  148. RSpec::Matchers.define :have_succeded do
  149. match do |cli|
  150. @actual = cli.exit_status
  151. @expected = '0 exit code'
  152. @actual.zero?
  153. end
  154. end
  155. RSpec::Matchers.define :have_failed do
  156. match do |cli|
  157. @actual = cli.exit_status
  158. @expected = 'non-0 exit code'
  159. @actual.positive?
  160. end
  161. end
  162. RSpec::Matchers.define :have_exited_with do |expected|
  163. match do |cli|
  164. @actual = cli.exit_status
  165. if expected.is_a?(ExecutionStatus)
  166. expected.validates?(@actual)
  167. else
  168. @actual == expected
  169. end
  170. end
  171. end

No Description

Contributors (1)