Skip to content

Double output #97

@schneems

Description

@schneems
# frozen_string_literal: true

require_relative "../spec_helper"

module DeadEnd

  require "pathname"
  require "optparse"
  class Cli
    attr_accessor :options, :file_name

    # Everything passed to the executable, does not include executable name
    def initialize(argv: , exit_obj: Kernel, io: $stdout, env: ENV)
      @options = {}
      @parser = nil
      options[:record_dir] = env["DEAD_END_RECORD_DIR"]
      options[:record_dir] = "tmp" if env["DEBUG"]
      options[:terminal] = DeadEnd::DEFAULT_VALUE

      @io = io
      @argv = argv
      @file_name = argv[0]
      @exit_obj = exit_obj
    end

    def call
      if file_name.nil? || file_name.empty?
        # Display help if raw command
        parser.parse! %w[--help]
      else
        self.parse
      end

      # Needed for testing since we fake exit
      return if options[:exit]

      file = Pathname(file_name)

      @io.puts "Record dir: #{options[:record_dir]}" if options[:record_dir]

      display = DeadEnd.call(
        source: file.read,
        filename: file.expand_path,
        terminal: options.fetch(:terminal, DeadEnd::DEFAULT_VALUE),
        record_dir: options[:record_dir]
      )

      if display.document_ok?
        @exit_obj.exit(0)
      else
        @exit_obj.exit(1)
      end
    end

    def parse
      parser.parse!(@argv)

      self
    end

    def parser
      @parser ||= OptionParser.new do |opts|

        opts.banner = <<~EOM
          Usage: dead_end <file> [options]

          Parses a ruby source file and searches for syntax error(s) such as
          unexpected `end', expecting end-of-input.

          Example:

            $ dead_end dog.rb

            # ...

              ❯ 10  defdog
              ❯ 15  end

          ENV options:

            DEAD_END_RECORD_DIR=<dir>

            Records the steps used to search for a syntax error
            to the given directory

          Options:
        EOM

        opts.version = DeadEnd::VERSION

        opts.on("--help", "Help - displays this message") do |v|
          @io.puts opts
          options[:exit] = true
          @exit_obj.exit
        end

        opts.on("--record <dir>", "Records the steps used to search for a syntax error to the given directory") do |v|
          options[:record_dir] = v
        end

        opts.on("--terminal", "Enable terminal highlighting") do |v|
          options[:terminal] = true
        end

        opts.on("--no-terminal", "Disable terminal highlighting") do |v|
          options[:terminal] = false
        end
      end
    end
  end

  class FakeExit
    def initialize
      @called = false
      @value = nil
    end

    def exit(value = nil)
      @called = true
      @value = value
    end

    def called?
      @called
    end

    def value
      @value
    end
  end

  RSpec.describe Cli do
    it "DEAD_END_RECORD_DIR" do
      io = StringIO.new
      exit_obj = FakeExit.new
      cli = Cli.new(
        io: io,
        argv: [],
        env: {"DEAD_END_RECORD_DIR" => "hahaha"}
        exit_obj: exit_obj
      ).parse

      expect(exit_obj.called?).to be_falsey
      expect(cli.options[:record_dir]).to eq("hahaha")
    end

    it "--record-dir=<dir>" do
      io = StringIO.new
      exit_obj = FakeExit.new
      cli = Cli.new(
        io: io,
        argv: ["--record=lol"],
        exit_obj: exit_obj
      ).parse

      expect(exit_obj.called?).to be_falsey
      expect(cli.options[:record_dir]).to eq("lol")
    end

    it "terminal default to respecting TTY" do
      io = StringIO.new
      exit_obj = FakeExit.new
      cli = Cli.new(
        io: io,
        argv: [],
        exit_obj: exit_obj
      ).parse

      expect(exit_obj.called?).to be_falsey
      expect(cli.options[:terminal]).to eq(DeadEnd::DEFAULT_VALUE)
    end

    it "--terminal" do
      io = StringIO.new
      exit_obj = FakeExit.new
      cli = Cli.new(
        io: io,
        argv: ["--terminal"],
        exit_obj: exit_obj
      ).parse

      expect(exit_obj.called?).to be_falsey
      expect(cli.options[:terminal]).to be_truthy
    end

    it "--no-terminal" do
      io = StringIO.new
      exit_obj = FakeExit.new
      cli = Cli.new(
        io: io,
        argv: ["--no-terminal"],
        exit_obj: exit_obj
      ).parse

      expect(exit_obj.called?).to be_falsey
      expect(cli.options[:terminal]).to be_falsey
    end

    it "--help outputs help" do
      io = StringIO.new
      exit_obj = FakeExit.new
      Cli.new(
        io: io,
        argv: ["--help"],
        exit_obj: exit_obj
      ).call

      expect(exit_obj.called?).to be_truthy
      expect(io.string).to include("Usage: dead_end <file> [options]")
    end

    it "<empty args> outputs help" do
      io = StringIO.new
      exit_obj = FakeExit.new
      Cli.new(
        io: io,
        argv: [],
        exit_obj: exit_obj
      ).call

      expect(exit_obj.called?).to be_truthy
      expect(io.string).to include("Usage: dead_end <file> [options]")
    end
  end
end

Gives:

$ be rspec spec/unit/cli_spec.rb
--> /Users/rschneeman/Documents/projects/dead_end/spec/unit/cli_spec.rb

syntax error, unexpected ':', expecting end-of-input

    5  module DeadEnd
  133    RSpec.describe Cli do
  134      it "DEAD_END_RECORD_DIR" do
  137        cli = Cli.new(
❯ 138          io: io,
❯ 139          argv: [],
❯ 140          env: {"DEAD_END_RECORD_DIR" => "hahaha"}
❯ 141          exit_obj: exit_obj
  142        ).parse
  146      end
  225    end
  226  end

--> /Users/rschneeman/Documents/projects/dead_end/spec/unit/cli_spec.rb

syntax error, unexpected ':', expecting end-of-input

    5  module DeadEnd
  133    RSpec.describe Cli do
  134      it "DEAD_END_RECORD_DIR" do
  137        cli = Cli.new(
❯ 138          io: io,
❯ 139          argv: [],
❯ 140          env: {"DEAD_END_RECORD_DIR" => "hahaha"}
❯ 141          exit_obj: exit_obj
  142        ).parse
  146      end
  225    end
  226  end


An error occurred while loading ./spec/unit/cli_spec.rb.
Failure/Error: dead_end_original_load(file)

SyntaxError:
  /Users/rschneeman/Documents/projects/dead_end/spec/unit/cli_spec.rb:141: syntax error, unexpected local variable or method, expecting ')'
          exit_obj: exit_obj
          ^~~~~~~~
  /Users/rschneeman/Documents/projects/dead_end/spec/unit/cli_spec.rb:225: syntax error, unexpected `end', expecting end-of-input
    end
    ^~~
# ./lib/dead_end/auto.rb:15:in `load'
# ./lib/dead_end/auto.rb:15:in `load'
# ./lib/dead_end/auto.rb:45:in `load'
No examples found.

Finished in 0.00004 seconds (files took 0.16909 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions