Module: RSpecCommand

Extended by:
RSpec::SharedContext
Defined in:
lib/rspec_command.rb,
lib/rspec_command/rake.rb,
lib/rspec_command/match_fixture.rb

Overview

An RSpec helper module for testing command-line tools.

Examples:

Enable globally

RSpec.configure do |config|
  config.include RSpecCommand
end

Enable for a single example group

describe 'myapp' do
  command 'myapp --version'
  its(:stdout) { it_expected.to include('1.0.0') }
end

Since:

  • 1.0.0

Defined Under Namespace

Modules: Rake

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#fixture_rootString (readonly)

Base path for the fixtures directory. Default value is 'fixtures'.

Examples:

let(:fixture_root) { 'data' }

Returns:

  • (String)


63
# File 'lib/rspec_command.rb', line 63

let(:fixture_root) { 'fixtures' }

#temp_pathString (readonly)

Path to the temporary directory created for the current example.

Returns:

  • (String)


54
55
56
# File 'lib/rspec_command.rb', line 54

let(:temp_path) do |example|
  example.[:rspec_command_temp_path]
end

Class Method Details

.command(cmd = nil, options = {}, &block) ⇒ Object

Run a command as the subject of this example. The command can be passed in as a string, array, or block. The subject will be a Mixlib::ShellOut object, all attributes from there will work with rspec-its.

Examples:

describe 'myapp' do
  command 'myapp show'
  its(:stdout) { is_expected.to match(/a thing/) }
end

Parameters:

  • cmd (String, Array) (defaults to: nil)

    Command to run. If passed as an array, no shell expansion will be performed.

  • options (Hash<Symbol, Object>) (defaults to: {})

    Options to pass to Mixlib::ShellOut.new.

  • block (Proc)

    Optional block to return a command to run.

Options Hash (options):

  • allow_error (Boolean)

    If true, don't raise an error on failed commands.

See Also:

  • #command

Since:

  • 1.0.0



275
276
277
278
279
280
281
282
# File 'lib/rspec_command.rb', line 275

def command(cmd=nil, options={}, &block)
  [:command] = true
  subject do |example|
    # If a block is given, use it to get the command.
    cmd = instance_eval(&block) if block
    command(cmd, options)
  end
end

.environment(variables) ⇒ Object

Set an environment variable for this example.

Examples:

describe 'myapp' do
  command 'myapp show'
  environment DEBUG: true
  its(:stderr) { is_expected.to include('[debug]') }
end

Parameters:

  • variables (Hash)

    Key/value pairs to set.

Since:

  • 1.0.0



346
347
348
349
350
351
352
# File 'lib/rspec_command.rb', line 346

def environment(variables)
  before do
    variables.each do |key, value|
      _environment[key.to_s] = value.to_s
    end
  end
end

.file(path, content = nil, &block) ⇒ Object

Create a file in the temporary directory for this example.

Examples:

describe 'myapp' do
  command 'myapp read data.txt'
  file 'data.txt', <<-EOH
a thing
EOH
  its(:exitstatus) { is_expected.to eq 0 }
end

Parameters:

  • path (String)

    Path within the temporary directory to write to.

  • content (String) (defaults to: nil)

    File data to write.

  • block (Proc)

    Optional block to return file data to write.

Since:

  • 1.0.0



297
298
299
300
301
302
303
304
305
# File 'lib/rspec_command.rb', line 297

def file(path, content=nil, &block)
  raise "file path should be relative the the temporary directory." if path == File.expand_path(path)
  before do
    content = instance_eval(&block) if block
    dest_path = File.join(temp_path, path)
    FileUtils.mkdir_p(File.dirname(dest_path))
    IO.write(dest_path, content)
  end
end

.fixture_file(path, dest = nil) ⇒ Object

Copy fixture data from the spec folder to the temporary directory for this example.

Examples:

describe 'myapp' do
  command 'myapp run test/'
  fixture_file 'test'
  its(:exitstatus) { is_expected.to eq 0 }
end

Parameters:

  • path (String)

    Path of the fixture to copy.

  • dest (String) (defaults to: nil)

    Optional destination path. By default the destination is the same as path.

Since:

  • 1.0.0



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/rspec_command.rb', line 319

def fixture_file(path, dest=nil)
  raise "file path should be relative the the temporary directory." if path == File.expand_path(path)
  before do |example|
    fixture_path = find_fixture(example.file_path, path)
    dest_path = dest ? File.join(temp_path, dest) : temp_path
    FileUtils.mkdir_p(dest_path)
    file_list = MatchFixture::FileList.new(fixture_path)
    file_list.files.each do |file|
      abs = file_list.absolute(file)
      if File.directory?(abs)
        FileUtils.mkdir_p(File.join(dest_path, file))
      else
        FileUtils.copy(abs , File.join(dest_path, file), preserve: true)
      end
    end
  end
end

Instance Method Details

#capture_output(&block) ⇒ String

Run a local block with $stdout and $stderr redirected to a strings. Useful for running CLI code in unit tests. The returned string has #stdout, #stderr and #exitstatus attributes to emulate the output from command.

Examples:

describe 'my rake task' do
  subject do
    capture_output do
      Rake::Task['mytask'].invoke
    end
  end
end

Parameters:

  • block (Proc)

    Code to run.

Returns:

  • (String)

Since:

  • 1.0.0



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rspec_command.rb', line 140

def capture_output(&block)
  old_stdout = $stdout.dup
  old_stderr = $stderr.dup
  # Potential future improvement is to use IO.pipe instead of temp files, but
  # that would require threads or something to read contiuously since the
  # buffer is only 64k on the kernel side.
  Tempfile.open('capture_stdout') do |tmp_stdout|
    Tempfile.open('capture_stderr') do |tmp_stderr|
      $stdout.reopen(tmp_stdout)
      $stdout.sync = true
      $stderr.reopen(tmp_stderr)
      $stderr.sync = true
      output = nil
      begin
        # Inner block to make sure the ensure happens first.
        begin
          block.call
        ensure
          # Rewind.
          tmp_stdout.seek(0, 0)
          tmp_stderr.seek(0, 0)
          # Read in the output.
          output = OutputString.new(tmp_stdout.read, tmp_stderr.read)
        end
      rescue Exception => e
        if output
          # Try to add the output so far as an attribute on the exception via
          # a closure.
          e.define_singleton_method(:output_so_far) do
            output
          end
        end
        raise
      else
        output
      end
    end
  end
ensure
  $stdout.reopen(old_stdout)
  $stderr.reopen(old_stderr)
end

#match_fixture(fixture_path, local_path = nil) ⇒ Object

Matcher to compare files or folders from the temporary directory to a fixture.

Examples:

describe 'myapp' do
  command 'myapp write'
  it { is_expected.to match_fixture('write_data') }
end

Since:

  • 1.0.0



122
123
124
# File 'lib/rspec_command.rb', line 122

def match_fixture(fixture_path, local_path=nil)
  MatchFixture.new(find_fixture(self.class.file_path), temp_path, fixture_path, local_path)
end