core: allow IO redirection of UI for testing
Use of $stdin, $stdout, and $stderr globals makes testing difficult. By exposing the IO objects as writable attributes, input/output can be more easily simulated using StringIO or doubles.
This commit is contained in:
parent
a8dcf92f14
commit
3b8bc2a433
|
@ -21,9 +21,22 @@ module Vagrant
|
||||||
# specific. See the implementation for more docs.
|
# specific. See the implementation for more docs.
|
||||||
attr_accessor :opts
|
attr_accessor :opts
|
||||||
|
|
||||||
|
# @return [IO] UI input. Defaults to `$stdin`.
|
||||||
|
attr_accessor :stdin
|
||||||
|
|
||||||
|
# @return [IO] UI output. Defaults to `$stdout`.
|
||||||
|
attr_accessor :stdout
|
||||||
|
|
||||||
|
# @return [IO] UI error output. Defaults to `$stderr`.
|
||||||
|
attr_accessor :stderr
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@logger = Log4r::Logger.new("vagrant::ui::interface")
|
@logger = Log4r::Logger.new("vagrant::ui::interface")
|
||||||
@opts = {}
|
@opts = {}
|
||||||
|
|
||||||
|
@stdin = $stdin
|
||||||
|
@stdout = $stdout
|
||||||
|
@stderr = $stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_copy(original)
|
def initialize_copy(original)
|
||||||
|
@ -132,7 +145,7 @@ module Vagrant
|
||||||
super(message)
|
super(message)
|
||||||
|
|
||||||
# We can't ask questions when the output isn't a TTY.
|
# We can't ask questions when the output isn't a TTY.
|
||||||
raise Errors::UIExpectsTTY if !$stdin.tty? && !Vagrant::Util::Platform.cygwin?
|
raise Errors::UIExpectsTTY if !@stdin.tty? && !Vagrant::Util::Platform.cygwin?
|
||||||
|
|
||||||
# Setup the options so that the new line is suppressed
|
# Setup the options so that the new line is suppressed
|
||||||
opts ||= {}
|
opts ||= {}
|
||||||
|
@ -144,11 +157,11 @@ module Vagrant
|
||||||
say(:info, message, opts)
|
say(:info, message, opts)
|
||||||
|
|
||||||
input = nil
|
input = nil
|
||||||
if opts[:echo]
|
if opts[:echo] || !@stdin.respond_to?(:noecho)
|
||||||
input = $stdin.gets
|
input = @stdin.gets
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
input = $stdin.noecho(&:gets)
|
input = @stdin.noecho(&:gets)
|
||||||
|
|
||||||
# Output a newline because without echo, the newline isn't
|
# Output a newline because without echo, the newline isn't
|
||||||
# echoed either.
|
# echoed either.
|
||||||
|
@ -206,7 +219,7 @@ module Vagrant
|
||||||
|
|
||||||
# Determine the proper IO channel to send this message
|
# Determine the proper IO channel to send this message
|
||||||
# to based on the type of the message
|
# to based on the type of the message
|
||||||
channel = type == :error || opts[:channel] == :error ? $stderr : $stdout
|
channel = type == :error || opts[:channel] == :error ? @stderr : @stdout
|
||||||
|
|
||||||
# Output! We wrap this in a lock so that it safely outputs only
|
# Output! We wrap this in a lock so that it safely outputs only
|
||||||
# one line at a time. We wrap this in a thread because as of Ruby 2.0
|
# one line at a time. We wrap this in a thread because as of Ruby 2.0
|
||||||
|
|
|
@ -40,23 +40,37 @@ describe Vagrant::UI::Basic do
|
||||||
subject.output("foo", new_line: false)
|
subject.output("foo", new_line: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "outputs to stdout" do
|
it "outputs to the assigned stdout" do
|
||||||
|
stdout = StringIO.new
|
||||||
|
subject.stdout = stdout
|
||||||
|
|
||||||
expect(subject).to receive(:safe_puts).with { |message, **opts|
|
expect(subject).to receive(:safe_puts).with { |message, **opts|
|
||||||
expect(opts[:io]).to be($stdout)
|
expect(opts[:io]).to be(stdout)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
subject.output("foo")
|
subject.output("foo")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "outputs to stderr for errors" do
|
it "outputs to stdout by default" do
|
||||||
|
expect(subject.stdout).to be($stdout)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "outputs to the assigned stderr for errors" do
|
||||||
|
stderr = StringIO.new
|
||||||
|
subject.stderr = stderr
|
||||||
|
|
||||||
expect(subject).to receive(:safe_puts).with { |message, **opts|
|
expect(subject).to receive(:safe_puts).with { |message, **opts|
|
||||||
expect(opts[:io]).to be($stderr)
|
expect(opts[:io]).to be(stderr)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
subject.error("foo")
|
subject.error("foo")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "outputs to stderr for errors by default" do
|
||||||
|
expect(subject.stderr).to be($stderr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "#detail" do
|
context "#detail" do
|
||||||
|
|
Loading…
Reference in New Issue