require 'spec_helper' class QueryCommandRun attr_accessor :stdout, :stderr, :exitstatus def initialize(args) out = StringIO.new err = StringIO.new $stdout = out $stderr = err begin Vcloud::Core::QueryCli.new(args).run @exitstatus = 0 rescue SystemExit => e # Capture exit(n) value. @exitstatus = e.status end @stdout = out.string.strip @stderr = err.string.strip $stdout = STDOUT $stderr = STDERR end end describe Vcloud::Core::QueryCli do subject { QueryCommandRun.new(args) } let(:mock_query) { double(:query, :run => true) } describe "normal usage" do context "when given no arguments" do let(:args) { %w{} } it "should pass nil type and empty options hash, then exit normally" do expect(Vcloud::Core::Query).to receive(:new). with(nil, {}).and_return(mock_query) expect(mock_query).to receive(:run) expect(subject.exitstatus).to eq(0) end end context "when given type" do let(:args) { %w{vApp} } it "should pass type and empty options hash, then exit normally" do expect(Vcloud::Core::Query).to receive(:new). with('vApp', {}).and_return(mock_query) expect(mock_query).to receive(:run) expect(subject.exitstatus).to eq(0) end end context "when asked to display version" do let(:args) { %w{--version} } it "should not call Query" do expect(Vcloud::Core::Query).not_to receive(:new) end it "should print version and exit normally" do expect(subject.stdout).to eq(Vcloud::Core::VERSION) expect(subject.exitstatus).to eq(0) end end context "when asked to display help" do let(:args) { %w{--help} } it "should not call Query" do expect(Vcloud::Core::Query).not_to receive(:new) end it "should print usage and exit normally" do expect(subject.stderr).to match(/\AUsage: \S+ \[options\] \[type\]\n/) expect(subject.exitstatus).to eq(0) end end end describe "simple arguments with values" do { :sortAsc => '--sort-asc', :sortDesc => '--sort-desc', :fields => '--fields', :filter => '--filter', }.each do |options_key, cli_arg| context "when given #{cli_arg}" do let(:args) { [cli_arg, 'giraffe'] } it "should pass :#{options_key} in options hash and exit normally" do expect(Vcloud::Core::Query).to receive(:new). with(nil, { options_key => 'giraffe' }). and_return(mock_query) expect(mock_query).to receive(:run) expect(subject.exitstatus).to eq(0) end end end end describe "complex arguments with values" do context "when given --output-format with mixed case value" do let(:args) { %w{--output-format MixedCaseValue} } it "should pass downcased value in options hash and exit normally" do expect(Vcloud::Core::Query).to receive(:new). with(nil, { :output_format => 'mixedcasevalue' }). and_return(mock_query) expect(mock_query).to receive(:run) expect(subject.exitstatus).to eq(0) end end end describe "incorrect usage" do shared_examples "print usage and exit abnormally" do |error| it "should not call Query" do expect(Vcloud::Core::Query).not_to receive(:new) end it "should print error message and usage" do expect(subject.stderr).to match(/\A\S+: #{error}\nUsage: \S+/) end it "should exit abnormally for incorrect usage" do expect(subject.exitstatus).to eq(2) end end context "when given more than type argument" do let(:args) { %w{type_one type_two} } it_behaves_like "print usage and exit abnormally", "too many arguments" end context "when given an unrecognised argument" do let(:args) { %w{--this-is-garbage} } it_behaves_like "print usage and exit abnormally", "invalid option: --this-is-garbage" end end describe "error handling" do context "when underlying code raises an exception" do let(:args) { %w{} } it "should print error without backtrace and exit abnormally" do expect(Vcloud::Core::Query).to receive(:new). with(nil, {}).and_raise("something went horribly wrong") expect(subject.stderr).to eq("something went horribly wrong") expect(subject.exitstatus).to eq(1) end end end end