-
-
Save matthijsgroen/5669777 to your computer and use it in GitHub Desktop.
Command line stubs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# a clever way to stub the calls to bundle: | |
# put this file in fixtures and give the proper permissions: | |
# chmod +x spec/fixtures/bundle | |
# see spec/publish_spec.rb for usage: | |
# add path to the bundle stub to the beginning of the PATH env. var. | |
# Now when bundle is called, this stub file is used. | |
command = File.basename(__FILE__) | |
require 'pathname' | |
Pathname.new(File.dirname(__FILE__)).join("#{command}_call.log").open('a') do |f| | |
f.puts "args: #{ARGV.join('|')}" | |
unless STDIN.tty? | |
f.puts "stdin: #{$stdin.read}" | |
end | |
end | |
require 'yaml' | |
call_configurations = Pathname.new(File.dirname(__FILE__)).join("#{command}_stub.yml") | |
if call_configurations.exist? | |
config = YAML.load call_configurations.read | |
config.each do |call_config| | |
if (call_config[:args] - ARGV).empty? | |
call_config[:stdout] && $stdout.puts(call_config[:stdout]) | |
call_config[:stderr] && $stderr.puts(call_config[:stderr]) | |
call_config[:file_output].each do |file_config| | |
Pathname.new(file_config[:file]).open('w') do |file| | |
file.puts file_config[:message] | |
end | |
end if call_config[:file_output] | |
exit call_config[:status_code] || 0 | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'fileutils' | |
require 'yaml' | |
# Command line stubs | |
# ================== | |
# | |
# This helper allows to create a shell command that acts as a stub/spy. | |
# | |
# Setup | |
# ----- | |
# | |
# first, you should declare a folder where the stubs should be placed. | |
# It is the best to use a non-existent folder. Since it will be created when the | |
# first stub is made, and is easy to cleanup. | |
# | |
# 1. `my_stub_folder = Pathname.new('tmp/stubs')` | |
# 2. `my_stub = create_stub_for('mail', my_stub_folder)` | |
# 3. When you execute your shell script that should use the | |
# stubs, be sure to give the stubfolder the most preference in the PATH | |
# `PATH=#{my_stub_folder}:$PATH my_shell_script_to_test.sh` | |
# | |
# Stubbing results of calls | |
# ------------------------- | |
# | |
# You can manipulate the results of a stub. | |
# These manipulations are scoped against call arguments: | |
# | |
# my_stub.with_args('some', 'arguments').action.action.action | |
# | |
# You can set multiple actions to a stub-call using chaining. | |
# | |
# ### Setting return status code: | |
# | |
# my_stub.with_args(...).and_exit_with(code) | |
# | |
# ### Output text to STDERR: | |
# | |
# my_stub.with_args(...).outputs_to_stderr(text) | |
# | |
# ### Writes a file: | |
# | |
# my_stub.with_args(...).outputs_to_file(filename, text) | |
# | |
# Verifying calls (using RSpec) | |
# ----------------------------- | |
# | |
# my_stub.should have_been_called_with('arg1', 'arg2') | |
# | |
# Verifying STDIN (using RSpec) | |
# ----------------------------- | |
# | |
# Sometimes you want to verify content that gets piped into a command: | |
# | |
# echo "content" | mail | |
# mail < some_file.txt | |
# | |
# So assert the content that gets piped-in: | |
# | |
# my_stub.should have_received_through_stdin(content) | |
# | |
# Cleanup | |
# ------- | |
# | |
# If you use a non-existent folder as target for the stubs (see setup section) | |
# removing stub files (calllog, stub, stub config) is as easy as: | |
# | |
# my_stub_folde.rmtree | |
# | |
module StubHelpers | |
def create_stub_for(command, folder) | |
folder.mkpath | |
FileUtils.cp('spec/fixtures/stub', folder.join(command).to_s) | |
Stub.new(folder.join("#{command}_stub.yml"), folder.join("#{command}_call.log")) | |
end | |
class Stub | |
def initialize(config_path, call_log_path) | |
@config_path = config_path | |
@call_log_path = call_log_path | |
@configuration = {} | |
end | |
def with_args(*args) | |
StubbedCall.new(self).args(*args) | |
end | |
def configure_status_code_for(args, status_code) | |
@configuration[args] ||= {} | |
@configuration[args][:status_code] = status_code | |
write_configuration | |
end | |
def configure_stderr_output_for(args, message) | |
@configuration[args] ||= {} | |
@configuration[args][:stderr] = message | |
write_configuration | |
end | |
def configure_stdout_output_for(args, message) | |
@configuration[args] ||= {} | |
@configuration[args][:stdout] = message | |
write_configuration | |
end | |
def configure_file_output_for(args, file, message) | |
@configuration[args] ||= {} | |
@configuration[args][:file_output] ||= [] | |
@configuration[args][:file_output] << { | |
file: file, | |
message: message | |
} | |
write_configuration | |
end | |
def has_been_called_with?(*args) | |
return false unless @call_log_path.exist? | |
# check in some file if arg occurs | |
@call_log_path.each_line do |line| | |
if match = /^args:\s(?<args>.*)$/.match(line) | |
call_args = match[:args].split('|') | |
return true if (args - call_args).empty? | |
end | |
end | |
false | |
end | |
def call_log | |
return false unless @call_log_path.exist? | |
@call_log_path.read | |
end | |
def has_received_through_stdin?(message) | |
return false unless @call_log_path.exist? | |
# check in some file if arg occurs | |
return true if stdin.find { |e| e.match message } | |
false | |
end | |
def stdin | |
content = @call_log_path.read | |
content[/^args:.*$/] = '' | |
content.split(/^stdin: /) | |
end | |
private | |
def write_configuration | |
structure = [] | |
@configuration.each do |args, results| | |
call = { | |
args: args, | |
}.merge results | |
structure << call | |
end | |
@config_path.open('w') do |f| | |
f.puts structure.to_yaml | |
end | |
end | |
class StubbedCall | |
def initialize(stub) | |
@stub = stub | |
end | |
def args(*args) | |
@args = args | |
self | |
end | |
def outputs_to_stderr(message) | |
@stub.configure_stderr_output_for(@args, message) | |
self | |
end | |
def outputs_to_stdout(message) | |
@stub.configure_stdout_output_for(@args, message) | |
self | |
end | |
def outputs_to_file(file, message) | |
@stub.configure_file_output_for(@args, file, message) | |
self | |
end | |
def and_exit_with(status_code) | |
@stub.configure_status_code_for(@args, status_code) | |
self | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment