Commit 7e1fe717 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Speed up options testing.

Reset the defaults every time the Options::Parser#parse method is
called.  This allows us to re-use the parser which is slow to instantiate.

Some tests still need to re-instatiate the parser every time - move
these to a separate suite, so only the tests that need it will run
slower.
parent da4eacac
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ module JsDuck
        @config = config_class

        @opts = Options::Record.new
        @defaults = {}

        @root_dir = @file.dirname(@file.dirname(@file.dirname(@file.dirname(__FILE__))))

@@ -28,6 +29,7 @@ module JsDuck
      # Parses array of command line options, returning
      # Options::Record object containing all the options.
      def parse(argv)
        init_defaults
        parse_options(argv)
        auto_detect_config_file unless @opts.config
        @opts
@@ -885,12 +887,27 @@ module JsDuck

      def attribute(name, value=nil)
        @opts.attribute(name, value)
        @defaults[name] = value
      end

      def validator(name, &block)
        @opts.validator(name, &block)
      end

      # Initializes attributes with default values.  This is needed to
      # be able to run the most tests without re-instantiating this
      # class every time.
      def init_defaults
        @defaults.each_pair do |name, value|
          @opts[name] = clone(value)
        end
      end

      # clones hashes and arrays.
      def clone(obj)
        (obj.is_a?(Array) || obj.is_a?(Hash)) ? obj.clone : obj
      end

      # Parses the given command line options
      # (could have also been read from config file)
      def parse_options(options)
+139 −0
Original line number Diff line number Diff line
require "jsduck/util/null_object"
require "jsduck/options/parser"

# Slower-running tests for Options::Parser, that require the parser to
# be instanciated before each test - which is sadly a bit slow.
describe JsDuck::Options::Parser do

  def mock_parse(methods, *argv)
    default_methods = {
      :dirname => Proc.new {|x| x },
      :expand_path => Proc.new {|x, pwd| x },
      :exists? => false,
    }
    file_class = JsDuck::Util::NullObject.new(default_methods.merge(methods))
    JsDuck::Options::Parser.new(file_class).parse(argv)
  end

  def parse(*argv)
    mock_parse({}, *argv)
  end

  describe :output_dir do
    it "is set with --output option" do
      parse("--output", "foo/").output_dir.should == "foo/"
    end

    it "is set with -o option" do
      parse("-o", "foo/").output_dir.should == "foo/"
    end

    it "is set to :stdout with -" do
      parse("--output", "-").output_dir.should == :stdout
    end

    it "is invalid when :stdout but not export" do
      parse("--output", "-").validate!(:output_dir).should_not == nil
    end

    it "is valid when :stdout and export" do
      parse("--output", "-", "--export", "full").validate!(:output_dir).should == nil
    end

    it "is invalid when no output dir specified" do
      parse().validate!(:output_dir).should_not == nil
    end

    it "is valid when output dir exists and is a directory" do
      m = {:exists? => Proc.new {|f| f == "foo/"}, :directory? => true}
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should == nil
    end

    it "is invalid when output dir is not a directory" do
      m = {:exists? => Proc.new {|f| f == "foo/"}, :directory? => false}
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should_not == nil
    end

    it "is valid when parent dir of output dir exists" do
      m = {
        :exists? => Proc.new do |fname|
          case fname
          when "foo/"
            false
          when "parent/"
            true
          else
            false
          end
        end,
        :dirname => Proc.new do |fname|
          case fname
          when "foo/"
            "parent/"
          else
            fname
          end
        end
      }
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should == nil
    end

    it "is invalid when parent dir of output dir is missing" do
      m = {:exists? => false}
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should_not == nil
    end
  end

  describe :template_dir do
    it "defaults to /template-min" do
      parse().template_dir.should =~ /template-min$/
    end

    it "is not validated when --export set" do
      opts = parse("--template", "foo", "--export", "full")
      opts.validate!(:template_dir).should == nil
    end

    it "is invalid when template dir has no /extjs dir" do
      m = {
        :exists? => false,
      }
      opts = mock_parse(m, "--template", "foo")
      opts.validate!(:template_dir).should_not == nil
    end

    it "is invalid when template dir has no /resources/css dir" do
      m = {
        :exists? => Proc.new {|fname| fname == "foo/extjs"},
      }
      opts = mock_parse(m, "--template", "foo")
      opts.validate!(:template_dir).should_not == nil
    end

    it "is valid when template dir contains both /extjs and /resouces/css dirs" do
      m = {
        :exists? => Proc.new {|fname| fname == "foo/extjs" || fname == "foo/resources/css" },
      }
      opts = mock_parse(m, "--template", "foo")
      opts.validate!(:template_dir).should == nil
    end
  end

  describe "--config" do
    it "interprets config options from config file" do
      file = JsDuck::Util::NullObject.new({
          :dirname => Proc.new {|x| x },
          :expand_path => Proc.new {|x, pwd| x },
          :exists? => Proc.new {|f| f == "conf.json" },
        })
      cfg = JsDuck::Util::NullObject.new({
          :read => ["-o", "foo", "file.js"]
        })

      opts = JsDuck::Options::Parser.new(file, cfg).parse(["--config", "conf.json"])
      opts.output_dir.should == "foo"
      opts.input_files.should == ["file.js"]
    end
  end

end
+47 −203
Original line number Diff line number Diff line
require "jsduck/util/null_object"
require "jsduck/options/parser"
require "jsduck/util/null_object"

describe JsDuck::Options::Parser do

  def mock_parse(methods, *argv)
    default_methods = {
  before :all do
    file_class = JsDuck::Util::NullObject.new({
        :dirname => Proc.new {|x| x },
        :expand_path => Proc.new {|x, pwd| x },
        :exists? => false,
    }
    file_class = JsDuck::Util::NullObject.new(default_methods.merge(methods))
    JsDuck::Options::Parser.new(file_class).parse(argv)
      })
    @parser = JsDuck::Options::Parser.new(file_class)
  end

  def parse(*argv)
    mock_parse({}, *argv)
    @parser.parse(argv)
  end

  describe :input_files do
@@ -39,71 +37,6 @@ describe JsDuck::Options::Parser do
    end
  end

  describe :output_dir do
    it "is set with --output option" do
      parse("--output", "foo/").output_dir.should == "foo/"
    end

    it "is set with -o option" do
      parse("-o", "foo/").output_dir.should == "foo/"
    end

    it "is set to :stdout with -" do
      parse("--output", "-").output_dir.should == :stdout
    end

    it "is invalid when :stdout but not export" do
      parse("--output", "-").validate!(:output_dir).should_not == nil
    end

    it "is valid when :stdout and export" do
      parse("--output", "-", "--export", "full").validate!(:output_dir).should == nil
    end

    it "is invalid when no output dir specified" do
      parse().validate!(:output_dir).should_not == nil
    end

    it "is valid when output dir exists and is a directory" do
      m = {:exists? => Proc.new {|f| f == "foo/"}, :directory? => true}
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should == nil
    end

    it "is invalid when output dir is not a directory" do
      m = {:exists? => Proc.new {|f| f == "foo/"}, :directory? => false}
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should_not == nil
    end

    it "is valid when parent dir of output dir exists" do
      m = {
        :exists? => Proc.new do |fname|
          case fname
          when "foo/"
            false
          when "parent/"
            true
          else
            false
          end
        end,
        :dirname => Proc.new do |fname|
          case fname
          when "foo/"
            "parent/"
          else
            fname
          end
        end
      }
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should == nil
    end

    it "is invalid when parent dir of output dir is missing" do
      m = {:exists? => false}
      mock_parse(m, "-o", "foo/").validate!(:output_dir).should_not == nil
    end
  end

  describe :export do
    it "accepts --export=full" do
      opts = parse("--export", "full")
@@ -128,20 +61,6 @@ describe JsDuck::Options::Parser do
    end
  end

  describe :title do
    it "defaults to 'Documentation - JSDuck'" do
      opts = parse()
      opts.title.should == 'Documentation - JSDuck'
      opts.header.should == "<strong>Documentation</strong> JSDuck"
    end

    it "sets both title and header" do
      opts = parse("--title", "Docs - MyApp")
      opts.title.should == "Docs - MyApp"
      opts.header.should == "<strong>Docs</strong> MyApp"
    end
  end

  describe :guides_toc_level do
    it "defaults to 2" do
      parse().guides_toc_level.should == 2
@@ -167,58 +86,61 @@ describe JsDuck::Options::Parser do
    end
  end

  describe :imports do
    it "defaults to empty array" do
      parse().imports.should == []
  describe :processes do
    it "defaults to nil" do
      opts = parse()
      opts.validate!(:processes).should == nil
      opts.processes.should == nil
    end

    it "expands into version and path components" do
      parse("--import", "1.0:/vers/1", "--import", "2.0:/vers/2").imports.should == [
        {:version => "1.0", :path => "/vers/1"},
        {:version => "2.0", :path => "/vers/2"},
      ]
    it "can be set to 0" do
      opts = parse("--processes", "0")
      opts.validate!(:processes).should == nil
      opts.processes.should == 0
    end

    it "expands pathless version number into just :version" do
      parse("--import", "3.0").imports.should == [
        {:version => "3.0"},
      ]
    end
    it "can be set to any positive number" do
      opts = parse("--processes", "4")
      opts.validate!(:processes).should == nil
      opts.processes.should == 4
    end

  describe :search do
    it "defaults to empty hash" do
      parse().search.should == {}
    it "can not be set to a negative number" do
      opts = parse("--processes", "-6")
      opts.validate!(:processes).should_not == nil
    end
  end

    it "sets :url from --search-url" do
      parse("--search-url", "example.com").search[:url].should == "example.com"
  describe :title do
    it "defaults to 'Documentation - JSDuck'" do
      opts = parse()
      opts.title.should == 'Documentation - JSDuck'
      opts.header.should == "<strong>Documentation</strong> JSDuck"
    end

    it "sets :product and :version from --search-domain" do
      opts = parse("--search-domain", "Touch/2.0")
      opts.search[:product].should == "Touch"
      opts.search[:version].should == "2.0"
    it "sets both title and header" do
      opts = parse("--title", "Docs - MyApp")
      opts.title.should == "Docs - MyApp"
      opts.header.should == "<strong>Docs</strong> MyApp"
    end
  end

  describe :external_classes do
    it "contain Object and Array by default" do
      classes = parse().external_classes
      classes.should include("Object")
      classes.should include("Array")
  describe :imports do
    it "defaults to empty array" do
      parse().imports.should == []
    end

    it "can be used multiple times" do
      classes = parse("--external", "Foo", "--external", "Bar").external_classes
      classes.should include("Foo")
      classes.should include("Bar")
    it "expands into version and path components" do
      parse("--import", "1.0:/vers/1", "--import", "2.0:/vers/2").imports.should == [
        {:version => "1.0", :path => "/vers/1"},
        {:version => "2.0", :path => "/vers/2"},
      ]
    end

    it "can be used with comma-separated list" do
      classes = parse("--external", "Foo,Bar").external_classes
      classes.should include("Foo")
      classes.should include("Bar")
    it "expands pathless version number into just :version" do
      parse("--import", "3.0").imports.should == [
        {:version => "3.0"},
      ]
    end
  end

@@ -254,66 +176,6 @@ describe JsDuck::Options::Parser do
    end
  end

  describe :processes do
    it "defaults to nil" do
      opts = parse()
      opts.validate!(:processes).should == nil
      opts.processes.should == nil
    end

    it "can be set to 0" do
      opts = parse("--processes", "0")
      opts.validate!(:processes).should == nil
      opts.processes.should == 0
    end

    it "can be set to any positive number" do
      opts = parse("--processes", "4")
      opts.validate!(:processes).should == nil
      opts.processes.should == 4
    end

    it "can not be set to a negative number" do
      opts = parse("--processes", "-6")
      opts.validate!(:processes).should_not == nil
    end
  end

  describe :template_dir do
    it "defaults to /template-min" do
      parse().template_dir.should =~ /template-min$/
    end

    it "is not validated when --export set" do
      opts = parse("--template", "foo", "--export", "full")
      opts.validate!(:template_dir).should == nil
    end

    it "is invalid when template dir has no /extjs dir" do
      m = {
        :exists? => false,
      }
      opts = mock_parse(m, "--template", "foo")
      opts.validate!(:template_dir).should_not == nil
    end

    it "is invalid when template dir has no /resources/css dir" do
      m = {
        :exists? => Proc.new {|fname| fname == "foo/extjs"},
      }
      opts = mock_parse(m, "--template", "foo")
      opts.validate!(:template_dir).should_not == nil
    end

    it "is valid when template dir contains both /extjs and /resouces/css dirs" do
      m = {
        :exists? => Proc.new {|fname| fname == "foo/extjs" || fname == "foo/resources/css" },
      }
      opts = mock_parse(m, "--template", "foo")
      opts.validate!(:template_dir).should == nil
    end
  end

  describe "--debug" do
    it "is equivalent of --template=template --template-links" do
      opts = parse("--debug")
@@ -343,23 +205,6 @@ describe JsDuck::Options::Parser do
    end
  end

  describe "--config" do
    it "interprets config options from config file" do
      file = JsDuck::Util::NullObject.new({
          :dirname => Proc.new {|x| x },
          :expand_path => Proc.new {|x, pwd| x },
          :exists? => Proc.new {|f| f == "conf.json" },
        })
      cfg = JsDuck::Util::NullObject.new({
          :read => ["-o", "foo", "file.js"]
        })

      opts = JsDuck::Options::Parser.new(file, cfg).parse(["--config", "conf.json"])
      opts.output_dir.should == "foo"
      opts.input_files.should == ["file.js"]
    end
  end

  describe :verbose do
    it "defaults to false" do
      parse().verbose.should == false
@@ -472,5 +317,4 @@ describe JsDuck::Options::Parser do
    end
  end


end