#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'spec_helper'
require "stringio"
require 'chef-dk/command/generate'

class ChefDK::Command::GeneratorCommands::Example < ChefDK::Command::GeneratorCommands::Base

  option :one,
    long:         "--option-one",
    description:  "one"

  option :two,
    long:         "--option-two",
    description:  "two"

  option :arg,
    short:        "-a ARG",
    long:         "--arg ARG",
    description:  "an option that takes an argument"

  def initialize(argv)
    super # required by mixlib-cli
    @argv = argv
  end

  def run
    parse_options(@argv)
    {:argv => @argv, :ran_cmd => "example"}
  end
end

describe ChefDK::Command::Generate do

  # Use a subclass so we have a clean slate of defined generators
  let(:generator_class) { Class.new(ChefDK::Command::Generate) }

  let(:stdout_io) { StringIO.new }
  let(:stderr_io) { StringIO.new }

  def stdout
    stdout_io.string
  end

  def stderr
    stderr_io.string
  end

  subject(:generate) do
    g = generator_class.new
    allow(g).to receive(:stdout).and_return(stdout_io)
    allow(g).to receive(:stderr).and_return(stderr_io)
    g
  end

  it "has a list of generators" do
    expect(generator_class.generators).to eq([])
  end

  context "with a generator defined" do
    let(:expected_help_message) do
      <<-E
Usage: chef generate GENERATOR [options]

Available generators:
  example  this is a test
E
    end

    before do
      generator_class.generator(:example, :Example, "this is a test")
    end

    it "includes the generator in the list" do
      expect(generator_class.generators.size).to eq(1)
      generator_spec = generator_class.generators.first
      expect(generator_spec.name).to eq(:example)
      expect(generator_spec.class_name).to eq(:Example)
      expect(generator_spec.description).to eq("this is a test")
    end

    it "includes the generator in the help output" do
      expect(generator_class.banner).to eq(expected_help_message)
    end

    it "prints usage when running an unknown generator" do
      generate.run(%w[ancient-aliens])
      expect(stdout).to include(expected_help_message)
    end

    it "runs the generator sub-command" do
      result = generate.run(%w[example])
      expect(result[:ran_cmd]).to eq("example")
    end

    it "removes the subcommand name from argv" do
      result = generate.run(%w[example])
      expect(result[:argv]).to eq([])
    end

    it "passes extra arguments and options to the subcommand" do
      result = generate.run(%w[example argument_one argument_two --option-one --option-two])
      expect(result[:argv]).to eq(%w[argument_one argument_two --option-one --option-two])
    end

    describe "when an invalid option is passed to the subcommand" do

      it "prints usage and returns non-zero" do
        result = generate.run(%w[example --nope])
        expect(result).to eq(1)
        expect(stderr).to eq("ERROR: invalid option: --nope\n\n")
      end

    end

    describe "when an option requires an argument but none is given" do

      it "prints usage and returns non-zero" do
        result = generate.run(%w[example --arg])
        expect(result).to eq(1)
        expect(stderr).to eq("ERROR: missing argument: --arg\n\n")
      end

    end

  end
end