Module: RSpec::CapturingFormatter::WindowsCommandLine

Defined in:
lib/rspec/capturing_formatter/windows_command_line.rb

Overview

Builds rerun commands without exposing dynamic targets to cmd.exe parsing.

Constant Summary collapse

DECODE_ARGUMENT =
'ARGV[0]=ARGV.fetch(0).unpack1("m0").force_encoding("UTF-8")'
RUN_RSPEC =
'load(Gem.bin_path("rspec-core","rspec"))'
CMD_META =

Protect characters that cmd.exe interprets while parsing a pasted command.

"()[]^\"`<>&|;, *?\t"

Class Method Summary collapse

Class Method Details

.encoded_ruby_command(script, value) ⇒ Object

Dynamic values are encoded because cmd.exe expands paired percent signs and exclamation marks before an executable can receive them.



21
22
23
24
25
# File 'lib/rspec/capturing_formatter/windows_command_line.rb', line 21

def encoded_ruby_command(script, value)
  value = valid_value(value).encode(Encoding::UTF_8)
  bootstrap = "#{DECODE_ARGUMENT};#{script}"
  "ruby -e #{escape(bootstrap)} #{[value].pack("m0")}"
end

.escape(value) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/rspec/capturing_formatter/windows_command_line.rb', line 27

def escape(value)
  value = valid_value(value)
  if value.match?(/[%!]/)
    raise ArgumentError, "dynamic cmd.exe arguments containing percent signs or exclamation marks must be encoded"
  end

  # Build Windows argv quoting before escaping the cmd.exe layer. A literal
  # quote needs 2n + 1 backslashes; a closing quote after n backslashes needs 2n.
  quoted = +'"'
  backslashes = 0
  value.each_char do |character|
    if character == "\\"
      backslashes += 1
    elsif character == '"'
      quoted << ("\\" * (backslashes * 2 + 1)) << '"'
      backslashes = 0
    else
      quoted << ("\\" * backslashes) << character
      backslashes = 0
    end
  end
  quoted << ("\\" * (backslashes * 2)) << '"'

  quoted.each_char.map do |character|
    CMD_META.include?(character) ? "^#{character}" : character
  end.join
end

.rerun_command(value) ⇒ Object



15
16
17
# File 'lib/rspec/capturing_formatter/windows_command_line.rb', line 15

def rerun_command(value)
  encoded_ruby_command(RUN_RSPEC, value)
end